一.简介
Android6.0发布以来,在权限上做出了很大的变动,不再是之前的只要在manifest设置就可以任意获取权限,而是更加的注重用户的隐私和体验,不会再强迫用户因拒绝不该拥有的权限而导致的无法安装的事情,也不会再不征求用户授权的情况下,就可以任意的访问用户隐私,而且即使在授权之后也可以及时的更改权限。这就是6.0版本做出的更拥护和注重用户的一大体现。
Android6.0系统把权限分为两个级别:
一类是Normal Permissions,即普通权限,这类权限不会潜藏有侵害用户隐私和安全的问题,比如,访问网络的权限,访问WIFI的权限等。
一类是Dangerous Permissions,即危险权限,这类权限会直接的威胁到用户的安全和隐私问题,比如说访问短信,相册等权限,地理位置权限。
二.权限
<1> 普通权限举例
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
使用以上权限是不会威胁到用户安全的,所以这类权限是可以直接的在manifest里面直接的使用,而且在安装后也会直接的生效了。
<2> 危险权限(敏感权限)举例
SMS(短信)
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
**********************************************************************
STORAGE(存储卡)
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
**********************************************************************
CONTACTS(联系人)
READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/
************************************************************************
PHONE(手机)
READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
<uses-permission android:name="android.permission.USE_SIP"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
************************************************************************
CALENDAR(日历)
READ_CALENDAR
WRITE_CALENDAR
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
*************************************************************************
CAMERA(相机)
CAMERA
<uses-permission android:name="android.permission.CAMERA"/>
*************************************************************************
LOCATION(位置)
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
*************************************************************************
SENSORS(传感器)
BODY_SENSORS
<uses-permission android:name="android.permission.BODY_SENSORS"/>
**************************************************************************
MICROPHONE(麦克风)
RECORD_AUDIO
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
注意:
危险权限和普通权限也有区别,普通权限是单条的权限,而危险权限是以组展示的,也就是说,当你接受一个危险权限时,不但但接受的是界面上展示的这一个权限,而是它所在这个组里面的其他所有访问权限也将会被自动获取权限,比如,一旦WRITE_CONTACTS被授权了,App也有READ_CONTACTS和GET_ACCOUNTS的权限了。值得注意的是,这类权限也是需要在manifest中注册的。
三.Demo
写一个Demo,动态申请 联系人和相机的权限
清单文件
<!-- 手机联系人 读 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!-- 手机联系人 写 -->
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<!-- 手机联系人 获取 -->
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!-- 相机 -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 传感器 -->
<uses-permission android:name="android.permission.BODY_SENSORS"/>
工具类
package com.example.test;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class AndroidPermissionUtils {
/**
* 当前系统是否是Android 6.0及以上
*/
public static boolean isMarshmallow = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
/**
* Android 6.0及以上 检测是否具有某些权限
*/
public static boolean hasAndroidPermission(Context context, String[] permission) {
boolean has = true;
for (String per : permission) {
if (ContextCompat.checkSelfPermission(context, per) != PackageManager.PERMISSION_GRANTED) {
has = false;
break;
}
}
return has;
}
/**
* Android 6.0及以上 申请某些权限
*/
public static void requestAndroidPermission(Activity activity, int code, String[] permission) {
ActivityCompat.requestPermissions(activity, permission, code);
}
}
Activity
package com.example.test;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
public class PermissionActivity extends AppCompatActivity {
//手机联系人
private String permission1 = "android.permission.READ_CONTACTS";
private String[] permission11 = new String[]{permission1};//敏感权限
private int Code1 = 123;
//相机权限
private String permission2 = "android.permission.CAMERA";
private String[] permission22 = new String[]{permission2};//敏感权限
private int Code2 = 456;
//传感器
private String permission3 = "android.permission.BODY_SENSORS";
private String[] permission33 = new String[]{permission3};//敏感权限
private int Code3 = 789;
private String[] permission = new String[]{permission1, permission2, permission3};//总权限
private int Code = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);
initView();
}
/**
* 初始化各种View
*/
private void initView() {
initPermissions();
//手机联系人权限相关
TextView textView1 = findViewById(R.id.activity_permission_textview1);
textView1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
if (AndroidPermissionUtils.hasAndroidPermission(PermissionActivity.this, permission11)) {//有权限 直接操作
getPhone("6.0及以上有权限 直接操作");
} else {//没权限 申请
AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code1, permission11);
}
} else {//6.0以下 直接操作
getPhone("6.0以下 直接操作");
}
}
});
//相机权限相关
TextView textView2 = findViewById(R.id.activity_permission_textview2);
textView2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
if (AndroidPermissionUtils.hasAndroidPermission(PermissionActivity.this, permission22)) {//有权限 直接操作
getCamera("6.0及以上有权限 直接操作");
} else {//没权限 申请
AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code2, permission22);
}
} else {//6.0以下 直接操作
getCamera("6.0以下 直接操作");
}
}
});
//传感器权限相关
TextView textView3 = findViewById(R.id.activity_permission_textview3);
textView3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
if (AndroidPermissionUtils.hasAndroidPermission(PermissionActivity.this, permission33)) {//有权限 直接操作
getSensors("6.0及以上有权限 直接操作");
} else {//没权限 申请
AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code3, permission33);
}
} else {//6.0以下 直接操作
getSensors("6.0以下 直接操作");
}
}
});
}
/**
* 手机联系人
*/
private void getPhone(String type) {
Log.d("PermissionActivity", "手机联系人type----:" + type);
ArrayList<HashMap<String, String>> list = readContact();
int count = list.size();
StringBuilder sb = new StringBuilder();
sb.append("当前设备联系人数:" + count + "\n\n\n");
for (int i = 0; i < count; i++) {
HashMap<String, String> map = list.get(i);
String name = map.get("name");
String phone = map.get("phone");
sb.append("姓名:" + name + " 手机号:" + phone + "\n\n\n");
}
String result = sb.toString();
Log.d("PermissionActivity", "手机联系人result----:" + result);
}
/**
* 相机权限
*/
private void getCamera(String type) {
Log.d("PermissionActivity", "相机权限type----:" + type);
}
/**
* 传感器权限
*/
private void getSensors(String type) {
Log.d("PermissionActivity", "传感器权限type----:" + type);
}
/**
* 初始化时申请三个权限
*/
private void initPermissions() {
if (AndroidPermissionUtils.isMarshmallow) {//6.0及以上
AndroidPermissionUtils.requestAndroidPermission(PermissionActivity.this, Code, permission);
}
}
/**
* 权限回调
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.d("PermissionActivity", "权限回调requestCode----:" + requestCode);
Log.d("PermissionActivity", "权限回调permissions.toString()----:" + permissions.toString());
Log.d("PermissionActivity", "权限回调permissions.length----:" + permissions.length);
Log.d("PermissionActivity", "权限回调grantResults.toString()----:" + grantResults.toString());
Log.d("PermissionActivity", "权限回调grantResults.length----:" + grantResults.length);
if (Code1 == requestCode) {//联系人权限相关
if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {//同意了权限
getPhone("同意了权限——回调");
} else {//拒绝了权限
Log.d("PermissionActivity", "联系人权限相关 拒绝了权限——回调");
}
} else if (Code2 == requestCode) {//相机权限相关
if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {//同意了权限
getCamera("同意了权限——回调");
} else {//拒绝了权限
Log.d("PermissionActivity", "相机权限相关 拒绝了权限——回调");
}
} else if (Code3 == requestCode) {//传感器权限相关
if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {//同意了权限
getSensors("同意了权限——回调");
} else {//拒绝了权限
Log.d("PermissionActivity", "传感器权限相关 拒绝了权限——回调");
}
} else if (Code == requestCode) {//初始化申请的三个权限
if (grantResults.length == 3) {
if ((grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
getPhone("初始化——同意了权限——回调");
} else {
Log.d("PermissionActivity", "联系人权限相关 初始化—拒绝了权限——回调");
}
if ((grantResults[1] == PackageManager.PERMISSION_GRANTED)) {
getCamera("初始化——同意了权限——回调");
} else {
Log.d("PermissionActivity", "相机权限相关 初始化——拒绝了权限——回调");
}
if ((grantResults[2] == PackageManager.PERMISSION_GRANTED)) {
getSensors("初始化——同意了权限——回调");
} else {
Log.d("PermissionActivity", "传感器权限相关 初始化——拒绝了权限——回调");
}
}
}
}
/**
* 获取当前设备联系人信息
* 1.从raw_contacts中读取联系人的id("contact_id")
* 2.根据contact_id从data表中查询出相应的电话号码和联系人名称
* 3.根据mimetype来区分哪个是联系人,哪个是电话号码
*/
private ArrayList<HashMap<String, String>> readContact() {
Uri rawContactsUri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri dataUri = Uri.parse("content://com.android.contacts/data");
ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
//从raw_contacts中读取联系人的id("contact_id")
Cursor rawContactsCursor = getContentResolver().query(rawContactsUri, new String[]{"contact_id"}, null, null, null);
if (rawContactsCursor != null) {
while (rawContactsCursor.moveToNext()) {
String contactId = rawContactsCursor.getString(0);
//根据contact_id从data表中查询出相应的电话号码和联系人名称, 实际上查询的是视图view_data
Cursor dataCursor = getContentResolver().query(dataUri, new String[]{"data1", "mimetype"}, "contact_id=?", new String[]{contactId}, null);
if (dataCursor != null) {
HashMap<String, String> map = new HashMap<String, String>();
while (dataCursor.moveToNext()) {
String data1 = dataCursor.getString(0);
String mimetype = dataCursor.getString(1);
if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
map.put("phone", data1);
} else if ("vnd.android.cursor.item/name".equals(mimetype)) {
map.put("name", data1);
}
}
list.add(map);
dataCursor.close();
}
}
rawContactsCursor.close();
}
return list;
}
}
注意
<1> 敏感权限动态申请一个分组下只申请一个就好。
<2> 权限回调方法中可以根据requestCode判断具体是申请的那个敏感权限,进而判断是同意了还是拒绝了。
附:官网:https://developer.android.google.cn/about/versions/marshmallow