Android--6.0运行时权限处理

一、概述

Andorid6.0版本自发布以来,相信不少开发者对于Android6.0版本来说,最大的手头工作无非就是做好6.0申请权限的工作,我们一旦没动态申请权限的话,那么将会报出一系列异常。当然有些权限的需要我们去动态申请的,而有些是不需要的,那么,这里估计会有人问:哪些需要或者哪些不需要?其实说白了,需要我们动态去申请的权限是属于危险权限,而我们不需要去动态申请的权限则是普通权限。下面我们将会介绍。所以,我们开发者有务必对6.0新版本sdk带来权限机制的变化。好的,那么今天我们将介绍Andorid6.0带来的运行时权限的一些处理。


二、运行时权限的变化

新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是Normal Permissions正常的权限,这类权限一般不涉及用户隐私,是不需要用户进行授权的,比如手机震动、访问网络等,这类权限也是属于我们文章中概述介绍的非6.0该有申请的权限;另一类是Dangerous Permission危险的权限,一般是涉及到用户隐私的,需要用户进行授权,比如读取sdcard、访问通讯录等,这类权限正好是我们6.0新版本所需要申请的权限。


三、Normal Permissions权限和Dangerous Permissions列表

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_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: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: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

PS:Normal Permissions普通权限是不需要我们在Andorid6.0去动态申请权限的,因为他属于普通权限,一般如果需要用到,我们直接在清单文件里面添加即可。Dangerous Permissions危险权限,则是需要我们在Android6.0中去动态申请权限的。看到Dangerous Permissions危险权限的时候,大家有没有发现都是一组一组的,没错,正是如此!其实之所以一组一组的,是因为Google故意设计的。

那么估计会有人问到,分组的权限机智对于我们开发者有影响吗,确实是有的,好比你现在拿一只安卓6.0版本的手机在运行程序,如果你申请某个危险的权限,假设你的app早已被用户授权了同一组的某个危险权限,那么系统会立即授权,而不需要用户去点击授权。比如你的app对READ_CONTACTS已经授权了,当你的app申请WRITE_CONTACTS时,系统会直接授权通过。此外,对于申请时弹出的dialog上面的文本说明也是对整个权限组的说明,而不是单个权限(ps:这个dialog是不能进行定制的)。

最后值得注意的是:我们在Android6.0申请危险权限的时候,我们要根据需求从而申请对应的权限列表,不能申请错误的权限列表哦!否则会出现一些错误,有关对应的权限名称,可自行上网百度。


四、相关的API以及动态申请权限的步骤

大概的步骤分为:检查权限--申请权限--处理申请权限的回调事件,其中,还有一个申请权限时的拒绝事件,也就是说点击了拒绝申请权限的事件,通常这个容易开开发者忽略,不过下面我们将会讲到。首先我们先来看看申请权限的几个基本步骤:


1、检查权限

if (ContextCompat.checkSelfPermission(MainActivity.this, CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {

}
这里主要涉及到了一个API:  ContextCompat. checkSelfPermission主要是用于检测当前某个权限是否已经被赋予了。如果当前权限不被 PackageManager.PERMISSION_GRANTED所赋予了,我们就需要对他进行权限的申请。


2、申请权限

ActivityCompat.requestPermissions(MainActivity.this, new String[]{CALL_PHONE}, MY_PERMISSIONS_REQUEST_CALL_PHONE);
该方法是用来申请权限的, 第一个参数是Context;第二个参数是需要申请的权限的字符串数组;第三个参数为requestCode,主要用于回调的时候检测。也就是我们自己定义的一个结果码,可以从方法名 requestPermissions 以及第二个参数看出,是支持一次性申请多个权限的,因为他是数组,系统会通过对话框 逐一 询问用户是否授权。


3、处于申请权限回调事件

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_CALL_PHONE: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    CallPhone();
                } else {
                    Toast.makeText(this, "授权失败!", Toast.LENGTH_LONG).show();
                }
                break;
            }
        }
    }
对于申请权限的回调事件,我们首先先判断一个和我们申请权限的结果码是否一致,如果一致的话,才能对我们申请的结果进行处理,这里的CallPhone方法我们主要是模拟打电话。具体代码下面会给出。


4、最后有一个API值得提醒一下,就是文章中所说的拒绝回调事件,不知道大家记起来了没有,在文章中曾说过,没记得没关系,下面我将为大家隆重介绍。

if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, CALL_PHONE)) {
}
该方法就是我们讲的拒绝权限申请回调事件,比如用户现在点击拒绝了,他会立刻执行到申请回调事件中的失败事件,在该事件中我们一般提示用户一下申请拒绝就可以了。然后等到第二次申请权限的时候,就会立刻执行 shouldShowRequestPermissionRationale方法体,在这个方法体中你需要给用户一个解释,为什么要授权,则使用该方法。一般在开发当中,我们可以在该方法体中用Toast提示用户说--请同意授权后,
才能拨打电话,这是常见的用法之一,但是还有一种比较流氓的手法,就是直接打开手机的设置面板,让用户手动开启该权限,这种做法确实比较流氓的,哈哈....下面最终案例里面会有涉及到这种用法,这么说一来,我确实也是流氓的大笑

好了,相关的API以及动态申请权限的步骤我已经介绍到这里。下面让我们一起来看看简单的例子。


五、简单的例子

这里我们将模拟打电话,大家也知道电话权限是属于危险权限的,在6.0版本中需要我们动态去申请该权限,所以我正好拿来这里做讲解,大家顺便看看6.0打电话是如何处理动态申请权限的。

当然我们这里代码也是非常简单的,无非就是检查权限,申请权限,处理权限回调事件。

MainActivity文件

import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
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;

import static android.Manifest.permission.CALL_PHONE;

public class MainActivity extends AppCompatActivity {

    //初始按钮控件和申请权限结果码
    private Button call_phone;
    private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        call_phone = (Button) this.findViewById(R.id.call_phone);
        call_phone.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //这里我们将模拟申请打电话权限
                TellPhone();
            }
        });
    }

    private void TellPhone() {
        //检查当前是否有CALL_PHONE电话这个权限
        if (ContextCompat.checkSelfPermission(MainActivity.this, CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
            //用户拒绝申请该权限的回调事件
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, CALL_PHONE)) {
                //提示该用户拒绝了权限信息
                Toast.makeText(MainActivity.this, "请同意授权后,才能拨打电话", Toast.LENGTH_LONG).show();
                // 帮跳转到该应用的设置界面,让用户手动同意打开电话授权(这里采用了流氓做法....)
                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                Uri uri = Uri.fromParts("package", getPackageName(), null);
                intent.setData(uri);
                startActivity(intent);
                Log.i("申请拒绝", "申请拒绝");
            } else {
                Log.i("正在申请", "正在申请");
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{CALL_PHONE}, MY_PERMISSIONS_REQUEST_CALL_PHONE);
            }
        } else {
            Log.i("申请成功", "申请成功");
            CallPhone();
        }
    }

    //拨打电话
    private void CallPhone() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_CALL); // 设置动作
        Uri data = Uri.parse("tel:" + 10086); // 设置数据
        intent.setData(data);
        startActivity(intent);
    }

    //处理权限申请的回调事件
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            //如果当前跟我们申请权限的结果码一致,则立刻执行
            case MY_PERMISSIONS_REQUEST_CALL_PHONE: {
                //申请权限成功
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    CallPhone();
                } else {
                    //申请权限失败
                    Toast.makeText(this, "申请权限失败", Toast.LENGTH_LONG).show();
                }
                break;
            }
        }
    }
}
布局文件我就不贴了,没什么撒,就只有一个Button而已。

当我们在安卓6.0机器上运行的时候,点击按钮后会立刻弹出权限窗口,这时候你可以选择拒绝或者同意。

当你选择拒绝后会提示申请回调事件中的申请权限失败信息,此时我们还执行不到拒绝回调事件当中。拒绝回调事件会在拒绝后第二次打开时候才执行的。




当你选择同意后会立刻执行CallPhone方法拨打电话。



例子很简单,但是以后遇到6.0危险权限的时候,我们记得动态去申请对应的权限。好了,今天关于Andorid--6.0运行时权限的处理讲解到这里,希望对大家有所帮助!







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值