美文网首页
Andorid的权限控制

Andorid的权限控制

作者: CP9 | 来源:发表于2017-02-08 17:56 被阅读175次

    概述

    默认情况下,Android应用程序是没有任何授权的,当应用程序需要使用设备的任何受保护功能(发送网络请求,访问摄像机,发送短信等)时,必须从用户那里获得相应的权限。

    在Marshmallow之前,权限都在安装时在项目中的清单文件中定义。在Marshmallow之后,现在必须在运行时请求权限,然后才能使用。PermissionsDispatcher第三方库用于管理运行时权限。

    Marshmallow之前的权限控制

    当用户从Google Play商店安装应用程序时,系统会向用户显示该应用程序所需的权限列表(有些人将此称为“权限墙”),用户可以接受所有权限,然后继续安装应用程序或决定不安装应用程序。没有办法只授予该应用程序的某些权限,用户没有办法撤消在安装应用程序后的某些权限。

    关于系统的权限列表:permissions

    Marshmallow之后的权限控制

    Marshmallow引入了运行时权限的概念,意味着你的targetSdkVersion<23的话需要做兼容性处理。

    当你需要添加新权限时,请先检查是否属于PROTECTION_NORMAL
    。在Marshmallow中,Google已将某些权限指定为“安全”,并称为“常规权限”。 这些东西,比如ACCESS_NETWORK_STATE,INTERNET等。 在安装时自动授予常规权限,并且不会提示用户请求权限。

    常规权限必须在清单文件中定义:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.android.app.myapp" >
        
        <uses-permission android:name="android.permission.INTERNET" />
        ...
    </manifest>
    

    运行时权限

    这类权限将向用户显示一个对话框,类似于以下:


    runtime-permission.png
    1. 将运行时权限添加到清单文件中:
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.codepath.androidpermissionsdemo" >
    
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        ...
    </manifest>
    
    1. 你需要使用android.support.v4.app.ActivityCompat这个向系统申请权限的工具类,兼容了各种系统版本。如下:
    • ActivityCompat.requestPermissions向系统申请一个或一组权 限
    • ActivityCompat.checkSelfPermissionApp检查自己是否有某个权限
    • ActivityCompat.shouldShowRequestPermissionRationale判断弹出对话框中是否含有“不再询问”的选择框

    步骤

    1. 你要有一个运行Android 6.0系统的设备
    2. 将App的targetSdkVersion设置为23
    3. 把AndroidManifest.xml中申请的并且是危险的所有权限都列出来,用ActivityCompat.requestPermissions方法向系统申请权限
    4. 在所在的Activity中OverrideonRequestPermissionsResult方法接受系统权限申请的回调
    5. 处理回调,比如用户拒绝了某个权限,这时App可以弹出一个对话框描述一下App为何需要这个权限等等
    // MainActivity.java
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            // In an actual app, you'd want to request a permission when the user performs an action
            // that requires that permission.
            getPermissionToReadUserContacts();
        }
    
        // Identifier for the permission request
        private static final int READ_CONTACTS_PERMISSIONS_REQUEST = 1;
    
        // Called when the user is performing an action which requires the app to read the
        // user's contacts
        public void getPermissionToReadUserContacts() {
            // 1) Use the support library version ContextCompat.checkSelfPermission(...) to avoid
            // checking the build version since Context.checkSelfPermission(...) is only available
            // in Marshmallow
            // 2) Always check for permission (even if permission has already been granted)
            // since the user can revoke permissions at any time through Settings
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                    != PackageManager.PERMISSION_GRANTED) {
    
                // The permission is NOT already granted.
                // Check if the user has been asked about this permission already and denied
                // it. If so, we want to give more explanation about why the permission is needed.
                if (shouldShowRequestPermissionRationale(
                        Manifest.permission.READ_CONTACTS)) {
                    // Show our own UI to explain to the user why we need to read the contacts
                    // before actually requesting the permission and showing the default UI
                }
    
                // Fire off an async request to actually get the permission
                // This will show the standard permission request dialog UI
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
                        READ_CONTACTS_PERMISSIONS_REQUEST);
            }
        }
    
        // Callback with the request from calling requestPermissions(...)
        @Override
        public void onRequestPermissionsResult(int requestCode,
                                               @NonNull String permissions[],
                                               @NonNull int[] grantResults) {
            // Make sure it's our original READ_CONTACTS request
            if (requestCode == READ_CONTACTS_PERMISSIONS_REQUEST) {
                if (grantResults.length == 1 &&
                        grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "Read Contacts permission granted", Toast.LENGTH_SHORT).show();
                } else {
                    // showRationale = false if user clicks Never Ask Again, otherwise true
                    boolean showRationale = shouldShowRequestPermissionRationale( this, Manifest.permission.READ_CONTACTS);
    
                    if (showRationale) {
                       // do something here to handle degraded mode
                    } else {
                       Toast.makeText(this, "Read Contacts permission denied", Toast.LENGTH_SHORT).show();
                    }
                }
            } else {
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
    

    权限组

    相关权限分组到一个权限组。 当应用请求属于特定权限组(即READ_CONTACTS)的权限时,Android会向用户询问更高级别的组(CONTACTS)。 这样,当应用程序稍后需要WRITE_CONTACTS权限时,Android可以自动授予此权限,而不会提示用户。

    group-permission.png

    向后兼容

    1. 你的App指定的targetSdkVersion<23,不过你的设备或者模拟器是Marshmallow
      • 你的app会继续使用旧的权限模型
      • 将在安装时询问AndroidManifest中列出的所有权限。
      • 用户将能够在安装应用程序后撤消权限
      • 使用PermissionChecker.checkSelfPermission方法检查App自身有没有某一个权限,这个方法的返回结果只有三种:
        • PERMISSION_GRANTED: 已授权
        • PERMISSION_DENIED: 没有被授权
        • PERMISSION_DENIED_APP_OP: 没有被授权(如果targetSdkVersion小于23)
    2. 你的App指定的targetSdkVersion>=23,不过你的设备或者模拟器低于Marshmallow
      • 你的app会继续使用旧的权限模型
      • 将在安装时询问AndroidManifest中列出的所有权限。
      • 使用context.checkSelfPermission(permission)方法检查App自身有没有某一个权限。
    try {
        final PackageInfo info = context.getPackageManager().getPackageInfo(
            context.getPackageName(), 0);
        targetSdkVersion = info.applicationInfo.targetSdkVersion;
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    
    public boolean selfPermissionGranted(Context context, String permission) {
        // Android 6.0 以前,全部默认授权
        boolean result = true;
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
           if (targetSdkVersion >= Build.VERSION_CODES.M) {
                // targetSdkVersion >= 23, 使用Context#checkSelfPermission
                result = context.checkSelfPermission(permission)
                        == PackageManager.PERMISSION_GRANTED;
            } else {
                // targetSdkVersion < 23, 需要使用 PermissionChecker
                result = PermissionChecker.checkSelfPermission(context, permission)
                        == PermissionChecker.PERMISSION_GRANTED;
            }
        }
        return result;
    }
    

    存储权限

    重新思考您是否需要读取/写入存储权限(即android.permission.WRITE_EXTERNAL_STORAGE或android.permission.READ_EXTERNAL_STORAGE),它会为您提供SD卡上的所有文件。 相反,您应该使用Context上的方法来访问外部存储上特定于软件包的目录。 您的应用程序始终可以访问对这些目录的读/写,因此无需请求权限:

    // Application-specific call that doesn't require external storage permissions
    // Can be Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_PODCASTS, Environment.DIRECTORY_RINGTONES, 
    // Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_PICTURES, or Environment.MOVIES
    File dir = MyActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    

    相关文章

      网友评论

          本文标题:Andorid的权限控制

          本文链接:https://www.haomeiwen.com/subject/hbzvittx.html