《第一行程式碼》閱讀筆記(二十四)——Android動態請求許可權
首先本章就介紹了什麼是危險許可權,而不是危險許可權的就是普通許可權。那有那些危險許可權呢,不用記,需要的時候直接來這個表裡查。「Android中危險許可權列表」同時可以訪問http://developer.android.com/reference/android/Manifest.permission.html可以檢視Android系統中完整的許可權列表。
Demo
首先先建立專案,給佈局設定一個按鈕,就不說了。書上先做了一個錯誤示範,讓大家看看沒有許可權的時候,程式會怎麼報錯,有興趣的可以看看。這裡就直奔主題,大家先來看看,完整的Activity。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnCall = findViewById(R.id.btn_call); btnCall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1); } else { Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); // call(); } } }); } // private void call() { // try { // Intent intent = new Intent(Intent.ACTION_CALL); // intent.setData(Uri.parse("tel:10086")); // startActivity(intent); // } catch (Exception e) { // e.printStackTrace(); // } // } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // call(); } else { Toast.makeText(this, "You denied the permission", Toast.LENGTH_LONG).show(); } break; default: } } }
如果按照書中的寫法,封裝的call方法會報錯,這應該是新版本對動態獲取許可權的改變。所以筆者做了一些修改。
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
...
} else {
...
}
首先在點選的時候,通過ContextCompat.checkSelfPermission函式接受兩個引數,一個是環境,另個一個就是具體的許可權名,比如例子中的Manifest.permission.CALL_PHONE。然後用得到的返回值和PackageManager.PERMISSION_GRANTED進行判斷。
checkSelfPermission顧名思義就是檢查當前環境的許可權,而後面跟的引數就是需要檢查的許可權。而PackageManager.PERMISSION_GRANTED就是手機已經獲得的許可權。兩者對比,就知道當前的APP是否已經獲得了許可權。根據不同的結果進行接下來的操作。
例子中,如果已經獲得,就進行Call的動作。如果沒有,就通過ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1)
來申請,三個引數分別是當前環境、許可權名陣列和為一個請求碼,一般傳入1就行。這個1會在後面的onRequestPermissionsResult函式中用到。
requestPermissions方法呼叫後,系統會自動彈出一個請求,需要使用者確認,無論使用者是否確認,都會進入onRequestPermissionsResult函式,這是一個系統自動生成的函式,雖然沒有呼叫,但是會將授權的結果封裝在grantResults引數當中。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// call();
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_LONG).show();
}
break;
default:
}
}
然後進行判斷,如果結果集的長度大於零,就說明有許可權被申請。並取出第一位,因為我們只申請了一個許可權名,所以第一個就是我們申請的值,然後和手機的許可權進行比較。其實結果集是一串0和-1的集合,分別和PackageManager包中的兩個引數對應。
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_GRANTED = 0;
如果使用者同意,就進行操作就行了,如果不同意彈出一個toast提示。
requestCode用來判斷進入那個switch分支,用來後續多個許可權申請的不同提示或者操作。
注意
Android10讀寫檔案許可權請求bug——open failed: EACCES (Permission denied)