1. 程式人生 > 實用技巧 >《第一行程式碼》閱讀筆記(二十四)——Android動態請求許可權

《第一行程式碼》閱讀筆記(二十四)——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)