前言¶
在Android 6.0(API 級別 23)以下申請權限是非常簡單的,直接在AndroidManifest.xml這個配置文件中加入申請權限的列表就可以了,比如我要申請四個權限,如下:
<!--打電話-->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!--使用相機-->
<uses-permission android:name="android.permission.CAMERA" />
<!--寫入內存卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--讀取內存卡-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
但是在Android 6.0(API 級別 23)以上的版就不可以這樣申請了,因爲這樣申請權限對用戶來說是非常危險的,應用已安裝就獲取了全部權限,也不知道這些權限應用要來幹什麼,可能是用戶不希望發生的一些操作。所以在Android 6.0之後,一些危險的權限就要動態申請了,哪些是危險權限呢,下面是官方提供的一個需要動態申請的危險權限:
| 權限組 | 權限 |
|---|---|
| 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 |
如果要使用上面的權限,除了要在AndroidManifest.xml這個配置文件聲明,還要在Java代碼中增加動態申請。下面我們就介紹如何單個和多個權限動態申請。
單個權限的動態申請¶
比如我們的應用要打電話,打電話是一個危險權限.
- 首先需要動態申請
AndroidManifest.xml配置文件添加申請打電話權限的聲明,如下:
<!--打電話-->
<uses-permission android:name="android.permission.CALL_PHONE" />
- 然後在Java代碼中編寫一個動態申請打電話權限的方法,當我們需要打電話之前,先要調用這個方法獲取權限:
// 請求單個權限
private void request_permission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
!= PackageManager.PERMISSION_GRANTED) {
// 最後的請求碼是對應回調方法的請求碼
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CALL_PHONE}, 1001);
} else {
Toast.makeText(this, "你已經有權限了,可以直接撥打電話", Toast.LENGTH_LONG).show();
}
}
- 請求申請權限之後,當用戶同意或者拒絕權限之後,都會在請求權限的回調方法反饋,我們可以在這個回調方法中判斷是否已經授權,並做相關的操作:
// 請求權限回調方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1001:
// 1001的請求碼對應的是申請打電話的權限
// 判斷是否同意授權,PERMISSION_GRANTED 這個值代表的是已經獲取了權限
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(MainActivity.this, "你同意授權,可以打電話了", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "你不同意授權,不可以打電話", Toast.LENGTH_LONG).show();
}
break;
}
}
- 我們增加一個按鈕,讓這個按鈕的點擊事件調用我們的申請權限方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button request_permission_btn = (Button) findViewById(R.id.request_permission_btn);
// 點擊獲取單個權限
request_permission_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
request_permission();
}
});
}
- 在
activity_main中的界面代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.yeyupiaoling.testpermission.MainActivity">
<Button
android:id="@+id/request_permission_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="請求單個權限" />
</LinearLayout>
- 測試我們的程序,第二個按鈕時下一部分的,讀者目前可以不用理會。第一次申請的時候是沒有權限的,然後就會動態申請權限,用戶同意了就獲得了權限。第二次申請權限時,因爲第一次已經申請到了,所以可以直接使用了。

多個權限動態申請¶
- 多個權限申請也是一樣的,首先同樣需要動態申請
AndroidManifest.xml配置文件添加所有申請的權利,如下。值得注意的是WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE都是屬於STORAGE組的,在申請它們兩個的時候嗎,只要同意一個,系統會立即另外一個權限,不會再彈出權限授予詢問的對話框。
<!--使用相機-->
<uses-permission android:name="android.permission.CAMERA" />
<!--寫入內存卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!--讀取內存卡-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- 多個權限的申請就複雜一些,首先要先創建一個列表,把需要的申請的權限添加到這個列表中,最後統一提交申請:
// 請求多個權限
private void request_permissions() {
// 創建一個權限列表,把需要使用而沒用授權的的權限存放在這裏
List<String> permissionList = new ArrayList<>();
// 判斷權限是否已經授予,沒有就把該權限添加到列表中
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.CAMERA);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
// 如果列表爲空,就是全部權限都獲取了,不用再次獲取了。不爲空就去申請權限
if (!permissionList.isEmpty()) {
ActivityCompat.requestPermissions(this,
permissionList.toArray(new String[permissionList.size()]), 1002);
} else {
Toast.makeText(this, "多個權限你都有了,不用再次申請", Toast.LENGTH_LONG).show();
}
}
- 申請多個權限,在回調方法中也會反饋多個權限的申請結果,所以我們要判斷每個權限的申請結果,全部的權限都申請成功了,那纔是申請成功了:
// 請求權限回調方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 1002:
// 1002請求碼對應的是申請多個權限
if (grantResults.length > 0) {
// 因爲是多個權限,所以需要一個循環獲取每個權限的獲取情況
for (int i = 0; i < grantResults.length; i++) {
// PERMISSION_DENIED 這個值代表是沒有授權,我們可以把被拒絕授權的權限顯示出來
if (grantResults[i] == PackageManager.PERMISSION_DENIED){
Toast.makeText(MainActivity.this, permissions[i] + "權限被拒絕了", Toast.LENGTH_SHORT).show();
}
}
}
break;
}
}
- 我們同樣增加一個按鈕,讓這個按鈕的點擊事件調用我們的申請多個權限方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button request_permissions_btn = (Button) findViewById(R.id.request_permissions_btn);
// 點擊獲取多個權限
request_permissions_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
request_permissions();
}
});
}
- 在
activity_main中的界面代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.yeyupiaoling.testpermission.MainActivity">
<Button
android:id="@+id/request_permissions_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="請求多個權限" />
</LinearLayout>
- 效果展示,當我們點擊按鈕申請多個權限時,就會開始申請多個權限。如上面所說的讀取內存卡和寫入內存卡屬於一個組,所以我們在看到關於內存卡的只是申請一次,如果一個拒絕了,那就全部都拒絕了。
參考資料¶
- https://developer.android.com/guide/topics/security/permissions#normal-dangerous