博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android权限详解
阅读量:3747 次
发布时间:2019-05-22

本文共 11497 字,大约阅读时间需要 38 分钟。

使用权限

android应用默认是不使用任何的权限的,当我们使用某些功能的时候,会要求用户添加某些权限,方可使用。例如请求网络和写入文件等等。当我们使用某些权限的时候,只需要在Manifest使用
添加权限,例如:

我们为程序添加了读取联系人权限,当用户请求查看联系人时,程序会弹出请求权限的对话框进行询问是否对App进行授权(Android6.0以上并且targetSdkVersion为23会弹出提示框,后面会进行讲解)。

名词介绍

安全权限

对于安全权限来说,这样的权限使用不会对用户造成用户隐私的泄露,系统会自动在安装时授予该应用程序的权限。例如用户设置时区的权限就是安全的权限。

安全权限列表:

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

危险权限

对于危险权限来说,会涉及到用户的隐私信息和数据的存储,例如读取联系人权限和对用户文件读写权限。

像危险权限,采用动态申请的方式。用户在使用的时候应该先检查用户是否已经对改权限进行授权,之后方可使用,如何操作后文会详细讲解。
注意:不管是安全权限和普通权限都应该在AndroidManifest文件中进行注册。

权限组

在Android权限中,任何权限都属于权限组,当用户是运行的设备是Android6.0(API23),并且应用的targetSdkVersion 是 23 或更高版本,则当用户请求危险权限时系统会发生以下行为:

  • 如果应用请求其清单中列出的危险权限,而应用目前在权限组中没有任何权限,则系统会向用户显示一个对话框,描述应用要访问的权限组。对话框不描述该组内的具体权限。例如,如果应用请求 READ_CONTACTS 权限,系统对话框只说明该应用需要访问设备的联系信息。如果用户批准,系统将向应用授予其请求的权限。
  • 如果应用请求其清单中列出的危险权限,而应用在同一权限组中已有另一项危险权限,则系统会立即授予该权限,而无需与用户进行任何交互。例如,如果某应用已经请求并且被授予了 READ_CONTACTS 权限,然后它又请求 WRITE_CONTACTS,系统将立即授予该权限。 、

任何权限都可属于一个权限组,包括正常权限和应用定义的权限。但权限组仅当权限危险时才影响用户体验。可以忽略正常权限的权限组。

CALENDAR(日历)

READ_CALENDAR
WRITE_CALENDAR
CAMERA(相机)
CAMERA
CONTACTS(联系人)
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATION(位置)
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE(麦克风)
RECORD_AUDIO
PHONE(手机)
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS(传感器)
BODY_SENSORS
SMS(短信)
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGE(存储卡)
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

关于Android版本

Android 6.0(API 级别 23)或更高版本,并且应用的 targetSdkVersion 是 23 或更高版本

当处于这种情况下,用户安装App时,用户可以不授权任何权限即可安装。但是如果不是这种情况(如Android为6.0一下,或者targetSdkVersion为23以下),用户在安装应用的时候必须全部同意所有的权限,才可以安装。

6.0一下或者targe为23以下

用户运行程序时,当用户的接下来要执行一个危险的权限,例如:像程序中写入一个文件,这时我们必须要检查用户是否已经拥有了这个权限,如果用户没有开启这个权限并且还执行了相应的操作,程序会出现报错或者警告提示。

所以我们应该采取如下方案:

a、检查用户是否具有某个权限可以调用checkSelfPermission()方法

这里介绍两个常量

/**

* Permission check result: this is returned by {@link #checkPermission}
* if the permission has been granted to the given package.
*/
权限已经授权
public static final int PERMISSION_GRANTED = 0;

/** * Permission check result: this is returned by {@link #checkPermission} * if the permission has not been granted to the given package. */ 权限没有授权public static final int PERMISSION_DENIED = -1;

例:

if (ContextCompat.checkSelfPermission(MainActivity.this,        Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {            System.out.println("用户没有权限了");        } else {            System.out.println("已经有权限了");        }

当已经授权了,我们执行相应的操作即可,例如查看联系人、读写文件等操作。

b、当用户没有授权,我们应该发出请求授权的请求,去让用户手动授权

//第一次请求用户去授权

ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 2);

这里写图片描述

注意,上图是第一次请求授权,这个弹框是系统的弹框,用户不能去更改

c、当用户每次调用requestPermissions时,都会回调onRequestPermissionsResult方法。

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

第一个参数:requestCode即为requestPermissions请求的第三个参数,我们可以在这里判断是在哪进行请求的

第二个参数:permissions[]从名字就可以看出来这个是用户请求权限时回调的数组,里面存放的是你请求的所有权限。
第三个参数:int[] grantResults第三个参数与第二个参数相对应,分别为第二个参数所对应的是否用户授权的值,授权为0,没有授权为1。

例如(请求了单个权限):

ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, 2);

在onRequestPermissionsResult方法中:

requestCode=2;
permissions=android.permission.READ_CONTACTS
grantResults=-1(点击拒绝)

例如(请求了多个权限):

ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS

,Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2);

在onRequestPermissionsResult方法中:

requestCode=2;
permissions=android.permission.READ_CONTACTS,android.permission.WRITE_EXTERNAL_STORAGE
grantResults=-1(点击拒绝),0(点击了允许)

@Override    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {        int flag = -1;        switch (requestCode) {            case 2:                //单个权限                             if (grantResults.length > 0                            && grantResults[0] == PackageManager.PERMISSION_GRANTED){                     // 用户同意权限                } else {                    // 用户不同意权限                }                //多个权限                if (grantResults.length > 0) {                    for (int i = 0; i < grantResults.length; i++) {                        if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {                            flag = 0;                        } else {                            flag=-1;                            break;                        }                    }                }                if (flag==0){                    // 用户同意权限                }else {                    // 用户不同意权限                }            }        }    }

d、shouldShowRequestPermissionRationale,该方法返回一个boolean类型的值这个方法有一个特点,当用户第一次对某一个权限点击拒绝的时候,该方法返回true,当第二次用户再次点击拒绝的时候并且勾选了[不在提示]对话框。该方法返回的是false;

这里写图片描述

上图为第二次申请权限,因为系统已经检测到你已经拒绝过一次权限,所以第二次会弹出不在提示选框

当我们第二次请求权限的时候,我们可以在onRequestPermissionsResult方法中,观察是否为false,并且提醒用户,该权限的重要性,如果无法开启这个权限会严重影响app的使用。

完整代码逻辑,这里讲述的是一个页面中,同时申请了两个权限,缺一不可的情况下,用户可以根据自己的需求进行增加和删除。

package com.example.mac.studypermission1;import android.Manifest;import android.app.AlertDialog;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.content.pm.PackageManager;import android.net.Uri;import android.provider.Settings;import android.support.v4.app.ActivityCompat;import android.support.v4.content.ContextCompat;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.Toast;public class MainActivity extends AppCompatActivity {
private Button bt; private Button bt1; private String[] permissions = new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt = (Button) findViewById(R.id.bt); bt1 = (Button) findViewById(R.id.bt1); //第二次授权 bt1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2); } }); //第一次授权 bt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { boolean allPermissions = false; for (int i = 0; i < permissions.length; i++) { if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) == PackageManager.PERMISSION_GRANTED) { allPermissions = true; } else { allPermissions = false; break; } } if (allPermissions == false) { //应该请求授权 ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS , Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2); } else { System.out.println("以授权"); } } }); } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { int flag = -1; switch (requestCode) { case 2: { if (grantResults.length > 0) { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { flag = 0; } else { flag = -1; break; } } } if (flag == 0) { System.out.println("以授权"); } else { // 用户不同意权限,第二次shouldShowRequestPermissionRationale为false boolean isJump = false; for (int i = 0; i < permissions.length; i++) { //第二次还是拒绝权限,这时shouldShowRequestPermissionRationale为false,应该提醒用户,此权限的重要性 if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permissions[i]) == false) { isJump = true; } else { isJump = false; break; } } if (isJump) { AlertDialog.Builder builder = new AlertDialog.Builder( MainActivity.this); builder.setTitle("提示"); builder.setMessage("这是一个很重要的权限!"); builder.setIcon(R.mipmap.ic_launcher); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, "确定被点击", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivityForResult(intent, 10); dialog.dismiss(); } }); builder.setCancelable(false); builder.show(); } } } } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { boolean allPermissions = false; for (int i = 0; i < permissions.length; i++) { //这里从App的设置中心返回时,应该二次检察权限 if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) == PackageManager.PERMISSION_GRANTED) { allPermissions = true; } else { allPermissions = false; break; } } if (allPermissions == false) { //应该请求授权 ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS , Manifest.permission.WRITE_EXTERNAL_STORAGE}, 2); } else { System.out.println("以授权"); } super.onActivityResult(requestCode, resultCode, data); }}

Android5.1(API 级别 22)或更低版本,并且应用的 targetSdkVersion 是 22 或更低版本

则系统会在用户安装应用时要求用户授予权限。如果将新权限添加到更新的应用版本,系统会在用户更新应用时要求授予该权限。用户一旦安装应用,他们撤销权限的唯一方式是卸载应用。

关于Android 6.0(API 级别 23)或更高版本,并且应用的 targetSdkVersion 是 23 或更高版本的流程图

列表内容

微信公众号:

这里写图片描述

QQ群:365473065

参考文章

你可能感兴趣的文章
可爱二次元人物图的转换实现(利用opencv滑动条)
查看>>
java程序:让用户输入贷款总额和以年为单位的贷款期限,然后显示利率从5%到8%,每次递增1/8的过程中,每月的支付额和总偿还额。
查看>>
java程序:提示用户输入两个圆的中心坐标和各自的半径值,然后决定第二个圆是否在第一个圆内,还是和第一个圆重叠,如下图所示
查看>>
java程序计算数列的和
查看>>
java程序:判断回文数:编写一个java应用程序,判断从键盘输入的一个整数是否为回文数,并将这个数据和判断结果输出。
查看>>
java:猜数字游戏:计算机随机产生一个1-100之间的整数,然后提示用户猜测输入一个整数,并提示偏大还是偏小,根据猜测的次数显示不同的提示。
查看>>
java:成绩统计 :从键盘上输入若干学生(假设不超过100)的成绩,计算平均成绩,并输出高于平均分的学生人数及成绩。约定输入成绩为101时结束。
查看>>
java:模拟家庭买电视(调频道)
查看>>
‘strtok‘: This function or variable may be unsafe. Consider using strtok_s instead.
查看>>
去掉word数据中的其中一列
查看>>
【javaGUI】老婆信息管理系统(有登录注册功能)
查看>>
javase个人垃圾复习笔记01常用英文词汇关键字
查看>>
javase个人垃圾复习笔记02一些变量和修饰符
查看>>
javase个人垃圾复习笔记03Number & Math 类常用的一些方法,Character 方法
查看>>
javase个人垃圾复习笔记04Java String 类的api们
查看>>
javase个人垃圾复习笔记05Java StringBuffer 和 StringBuilder 类
查看>>
javase个人垃圾复习笔记06数组,继承
查看>>
javase个人垃圾复习笔记07 Date 类(以后要用就去查api文档吧哈哈哈)
查看>>
javase个人垃圾复习笔记08可变参数...和finalize() 方法,以及 Java Scanner 类
查看>>
javase个人垃圾复习笔记09Java 正则表达式
查看>>