一.簡介
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"/>
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvwVP9cWT0EFRNp3Y65ke4wmYwhGWhxGZzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYvwFd4VGdvwlMvw1ayFWbyVGdhd3P5YzNzUDMxEzMwkDM4EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
注意:
危險權限和普通權限也有差別,普通權限是單條的權限,而危險權限是以組展示的,也就是說,當你接受一個危險權限時,不但但接受的是界面上展示的這一個權限,而是它所在這個組裡面的其他所有通路權限也将會被自動擷取權限,比如,一旦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