Android 6.0 运行时权限解析

对于Android 6.0以下的系统,App在安装时会生成一个权限列表,用户只有在同意之后才能完成App的安装,使得我们想要使用某个App,就要忍受其一些不必要的权限,当然我们也可以对单个权限进行授权或者解除。

在Android 6.0开始,App可以直接安装,然后在运行时请求用户授予权限,系统会弹出一个对话框(这个Dialog不能由开发者定制)让用户决定是否授予某个权限给App。

Google将系统权限分为两类 一类是Normal Permissions,这类权限一般不涉及用户隐私,安装即授权,不需要每次使用时都检查权限,比如访问网络、蓝牙、震动等。 另一类是Dangerous Permission,一般是涉及到用户隐私的,需要用户进行授权,比如读写SDCard、发送短信、访问通讯录等。

Normal Permissions

ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS

Dangerous Permissions

group:com.google.android.gms.permission.CAR_INFORMATION
 permission:com.google.android.gms.permission.CAR_VENDOR_EXTENSION
  permission:com.google.android.gms.permission.CAR_MILEAGE
  permission:com.google.android.gms.permission.CAR_FUEL

group:android.permission-group.CONTACTS
  permission:android.permission.WRITE_CONTACTS
  permission:android.permission.GET_ACCOUNTS
  permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
  permission:android.permission.READ_CALL_LOG
  permission:android.permission.READ_PHONE_STATE
  permission:android.permission.CALL_PHONE
  permission:android.permission.WRITE_CALL_LOG
  permission:android.permission.USE_SIP
  permission:android.permission.PROCESS_OUTGOING_CALLS
  permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
  permission:android.permission.READ_CALENDAR
  permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
  permission:android.permission.CAMERA

group:android.permission-group.SENSORS
  permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
  permission:android.permission.ACCESS_FINE_LOCATION
  permission:com.google.android.gms.permission.CAR_SPEED
  permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
  permission:android.permission.READ_EXTERNAL_STORAGE
  permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
  permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
  permission:android.permission.READ_SMS
  permission:android.permission.RECEIVE_WAP_PUSH
  permission:android.permission.RECEIVE_MMS
  permission:android.permission.RECEIVE_SMS
  permission:android.permission.SEND_SMS
  permission:android.permission.READ_CELL_BROADCASTS

可通过以下命令行查看

adb shell pm list permissions -d -g

这里写图片描述

如果App运行在Android 6.0以上的系统中,如果申请某个危险的权限,假设App已被用户授予了同一组的某个危险权限,那么系统会立即授权而不需要用户再次确认。 此外,申请时弹出的对话框之上的权限说明也是对整个权限组的说明,而不是单个权限。 需要注意的是,如果App运行在Android 5.1 (API level 22)或更低级别的设备中,或者targetSdkVersion<=22时(此时设备可以是Android 6.0 (API level 23)或者更高),在系统中仍将采用旧的权限管理策略,系统会要求用户在安装的时候授予所有权限。

运行时权限涉及到的常量与方法有以下几个:

授权状态标记:

已被授权

PackageManager.PERMISSION_GRANTED

不被授权

PackageManager.PERMISSION_DENIED

检查某权限或权限组是否已被授予

public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)

请求权限

public static void requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final int requestCode)

当第一次权限申请被拒绝后,判断再次进行权限申请时是否可以对用户进行权限申请说明

public static boolean shouldShowRequestPermissionRationale(@NonNull Activity activity,@NonNull String permission)

权限申请结果回调

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults)

新建一个工程,进行拨打电话以及发送短信权限的申请操作

同样要在AndroidManifest中进行权限声明

 <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.SEND_SMS" />

确保此时targetSdkVersion要大于等于23

defaultConfig {
        applicationId "com.example.zy.myapplication"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

在布局中添加两个按钮

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.zy.myapplication.MainActivity">

    <Button
        android:id="@+id/btn_phone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="拨打电话" />

    <Button
        android:id="@+id/btn_sms"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送短信" />

</LinearLayout>

全部代码如下

package com.example.zy.myapplication;

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private final int REQUEST_CALL_PHONE = 1;

    private final int REQUEST_SEND_SMS = 2;

    private final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn_phone = (Button) findViewById(R.id.btn_phone);
        Button btn_sms = (Button) findViewById(R.id.btn_sms);
        btn_phone.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //检查是否已经被授予权限,如果没有则进行申请,有的话则直接打电话
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE)
                        != PackageManager.PERMISSION_GRANTED) {
                    //判断此时是否可以向用户说明为什么需要申请权限
                    //说明完之后可以再来调用requestPermissions进行权限申请
                    if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                            Manifest.permission.CALL_PHONE)) {
                        Toast.makeText(MainActivity.this, "我就是需要权限", Toast.LENGTH_SHORT).show();
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.CALL_PHONE}, REQUEST_CALL_PHONE);
                    } else {
                        ActivityCompat.requestPermissions(MainActivity.this,
                                new String[]{Manifest.permission.CALL_PHONE}, REQUEST_CALL_PHONE);
                    }
                } else {
                    callPhone();
                }
            }
        });
        btn_sms.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.SEND_SMS)
                        != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission.SEND_SMS}, REQUEST_SEND_SMS);
                } else {
                    sendSms();
                }
            }
        });
    }

    private void callPhone() {
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:" + "10086");
        intent.setData(data);
        startActivity(intent);
    }

    private void sendSms() {
        Toast.makeText(this, "被授予了权限,可以进行发送短信的操作", Toast.LENGTH_SHORT).show();
    }

    //permissions是申请时所包含的所有权限
    //grantResults是对应权限的处理结果
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_CALL_PHONE:
                for (String permission : permissions) {
                    Log.e(TAG + "--Phone", permission);
                }
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    callPhone();
                } else {
                    Toast.makeText(this, "拒绝授权", Toast.LENGTH_SHORT).show();
                }
                break;
            case REQUEST_SEND_SMS:
                for (String permission : permissions) {
                    Log.e(TAG + "--SMS", permission);
                }
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    sendSms();
                } else {
                    Toast.makeText(this, "拒绝授权", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
}

确保此时运行的设备系统版本为6.0或更高版本

这里写图片描述

代码下载地址:Android 6.0 运行时权限解析

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏上善若水

004-golang 正则表达式的使用

1628
来自专栏FreeBuf

深入挖掘APP克隆实验

0×00前言 在上一篇文章《WebView域控不严格读取内部私有文件实验》中,对webview跨域访问进行了简单的实验,后续决定深入挖掘一下APP克隆,之前文章...

22010
来自专栏技术小黑屋

检查Android是否具有摄像头

通常我们进行摄像头操作,如扫描二维码需要判断是否有后置摄像头(Rear camera),比如Nexus 7 一代就没有后置摄像头,这样在尝试使用的时候,我们需要...

642
来自专栏非著名程序员

Android M 权限最佳实践

前言 Google在Android 6.0 上开始原生支持应用权限管理,再不是安装应用时的一刀切。权限管理虽然很大程度上增加了用户的可操作性,但是却苦了广大An...

1979
来自专栏写写代码吃吃瓜

Android简易“吹一吹实现”以及录音和播放示例

1454
来自专栏Android学习之路

6.0 运行时权限处理

2118
来自专栏Android小菜鸡

自定义Androidk全量更新组件

  自动更新功能对于一个APP来说是必备的功能,特别是对于未投放市场下载的APP,每次都让用户删掉原来的,再下载新的版本,肯定是不合适的。

592
来自专栏Android小菜鸡

popupWindow的封装与学习

  本篇主要富含了对PopupWindow的封装,实现动画弹窗的例子。可用于相册选择、点赞等等。同时封装使用了建造者模式,对于补间动画的运用同样有较高的学习价值...

581
来自专栏增长技术

Android 6.0运行时权限理解

<protectionLevel>属性是必须的,告诉系统当app申请该权限的时候,要怎样通知用户。

541
来自专栏Android知识点总结

TI--安卓运行时权限完美封装

842

扫码关注云+社区