Android笔记— Android 权限详解


资料来源如下

  • 第一行代码(第二版)
  • android6.0运行时权限详解

编程环境

  • Android Studio 2.2.3

导语

  • 内容提供器是安全的应用间共享数据途径,在正式进入之前需要了解一下 Android 自6.0以来权限的变化

Android 权限详解


资料来源:

  • android6.0运行时权限详解
  • Develop-API Guides-系统权限
  • 第一行代码(第二版)

Android权限介绍

  • Android 是一个权限分隔的操作系统
    每个应用系统标识(Linux 用户 ID 和组 ID)不同。系统各部分标识亦不相同。Linux 据此将不同的应用以及应用与系统分隔开来。
    更详细的安全功能通过“权限”提供,权限 会限制特定进程可以执行的具体操作,并且根据 URI 权限授权临时访问特定的数据段

  • 权限声明
    最常见的权限声明在 AndroidManifest.xml 文件中一个或多个uses-permission 标记,

    • 例如 声明短信权限
      1
      2
      3
      4
      5
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.app.myapp" >
      <uses-permission android:name="android.permission.RECEIVE_SMS" />
      ...
      </manifest>
  • android 6.0 权限机制
    android 6.0之前 权限及在安装的时候,根据权限声明产生一个权限列表,用户只有在同意之后才能完成app的安装。
    android 6.0 以后 引入了 运行时权限 功能,应用所需权限不再一次性在安装时申请,而是在运行时需要用到那种权限向用户申请,同时用户也可以随时取消该授权

  • 权限分类

    • Normal Permissions(普通权限)
      不涉及用户隐私,不需要用户进行授权的,例如 手机震动、访问网络等
    • Dangerous Permission(危险权限)
      涉及到用户隐私的,需要用户进行授权,例如 读取sdcard、访问通讯录等
      危险权限组如表1

应用运行时申请权限(适用于 Android6.0 及以上版本)

  • 通过一个简单的实例来说明过程

    实例:

  • 拨打电话 CALL_PHONE _权限为例

    • 权限声明
      1
      <uses-permission android:name="android.permission.CALL_PHONE"/>
  • 拨打10010

    • 代码如下 构建一个隐式intent 启动拨打电话
      1
      2
      3
      Intent intent = new Intent(Intent.ACTION_CALL);
      intent.setData(Uri.parse("tel:10010"));
      startActivity(intent);
  • 在主界面上添加一个Button 在其onClick方法中拨打电话,运行程序!


  • 在An’d’roid 6.0 以下版本中 电话都可以正常拨出。Android 6.0 以上版本中 则可能会应用崩溃/无反应,查看logcat的打印日志可以看到 “Permission Denial”权限被禁止的信息,接下来尝试使用 运行时申请权限

  • 检查是否已获得授权
    int checkSelfPermission(Context context, String permission)方法

    • Context context context
      String permission 权限具体名称
      打电话对应 Manifest.permission.CALL_PHONE _
    • 方法返回 PERMISSION_GRANTED / PERMISSION_DENIED
    • 例程
      1
      2
      3
      4
      5
      6
      7
      8
      if(ContextCompat.checkSelfPermission
      (MainActivity.this,Manifest.permission.CALL_PHONE)
      !=PackageManager.PERMISSION_GRANTED)
      {
      ;
      }else {
      ;
      }
  • 申请权限
    void ActivityCompat.requestPermissions (Activity activity, String[] permissions, int requestCode)方法

    • Activity activity Activity实例
      String[] permissions 请求权限名
      int requestCode 请求码,大于0即可,对应在onRequestPermissionsResult 回掉方法中的requestCode

    • 例程

      1
      2
      ActivityCompat.requestPermissions(MainActivity.this,
      new String[]{Manifest.permission.CALL_PHONE},1 );
  • 授权后回掉
    无论用户是否授权都会进入回掉方法,需要重写该方法。
    void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)方法

    • int requestCode 在 requestPermissions 中传入的请求码
      String[] permissions 请求的权限,不为空
      int[] grantResults 授权结果 只有 PERMISSION_GRANTED / PERMISSION_DENIED 两个值

    • 例程

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      @Override
      public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
      switch (requestCode) {
      //请求码 1
      case 1:
      //授权结果(int) 的 长度是否大于0 与上 授权结果是否等于 PackageManager.PERMISSION_GRANTED
      if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
      //授权通过执行
      } else {
      //授权没有通过
      }
      break;
      default:
      }
      }
  • 当用户拒绝后再次询问
    boolean ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission) (真心太长了)

    • Activity activity Activity实例
      String permission 权限名称
      应用第一次需要授权时,用户授权,该方法返回false。当用户拒绝授权,下次需要该权限时,该方法会返回true
    • 例程
      1
      2
      3
      4
      5
      6
      7
       if (ActivityCompat.shouldShowRequestPermissionRationale
      (PermissionActivity.this,Manifest.permission.READ_CONTACTS))
      {
      //第二次询问用户是否授权
      }else{
      //用户依旧拒绝后操作
      }
  • 例程源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    }

    public void Button(View view){
    if(ContextCompat.checkSelfPermission(MainActivity.this,Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE},1 );
    }else {
    call();
    }

    }

    private void call() {
    try {
    Intent intent = new Intent(Intent.ACTION_CALL);
    intent.setData(Uri.parse("tel:10010"));
    startActivity(intent);
    } catch (SecurityException e) {
    e.printStackTrace();
    }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
    case 1:
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    call();
    } else {
    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
    }
    break;
    default:
    }
    }

    }
    1
    2
    3
    4
    5
    <Button
    android:onClick="Button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!" />