android 學習筆記之六 動態獲取權限

更多內容,請查看

https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en

除了下面的之外,在工作中發現

        Intent intentPermissions = new Intent(activity, PermissionCheckActivity.class);
        上面的intent不能傳輸權限

Intent intentPermissions=new Intent(activity.getIntent());
        intentPermissions.setClass(activity, PermissionCheckActivity.class);

這個intent 才能夠很好的傳輸權限

衆所周知,Android 6.0 相比之前的Android版本有一個很大的不同點,就是動態獲取權限。今天自己在做撥號功能時,正巧遇到這個問題, 順手記錄下在Android 6.0 上如何動態獲取權限。

下面從自己一開始的問題入手

實現撥號功能

說到撥號,一個 Intent 就搞定,代碼如下,

1
2
3
4
5
6
   private void callDirectly(String mobile){
        Intent intent = new Intent();
        intent.setAction("android.intent.action.CALL");
        intent.setData(Uri.parse("tel:" + mobile));
        mContext.startActivity(intent);
    }

當然 你可別忘了在 Manifest 文件中去聲明撥號的權限

1
<uses-permission android:name="android.permission.CALL_PHONE" />

問題

如果在Android6.0以前的設備上,上面的代碼都是沒有問題的,但是如果是在Android6.0設備上, 你就會發現,撥號鍵盤是不能正常吊起的,因爲 Android M 的權限是在運行時動態賦給用戶的。關於動態分配權限,一些同學可能不是很清楚。 這裏稍稍提一下 Android6.0 的權限動態分配。如果你只對最終的解決方案感興趣,可以跳過下面這節,直接去看解決方案

權限動態分配

在 Android6.0 之前,下載好一個應用程序,點擊安裝我們看到的大都是像這樣的界面。

permission

上圖分別是Nexus6和小米手機在安裝軟件時的界面。

在安裝時你會發現,手機操作系統會提示,這個軟件會索要了你手機的那些權限,並且給用一個列表進行展示,但是這些提示只是在安裝是提示,只要你點擊接受或者安裝, 表示你允許這個應用在可以獲取它申明的所有權限。一般很少有人在安裝時,會因爲看到某個應用因爲申請了某一個敏感權限而放棄安裝應用。因爲這個權限雖然敏感, 但是對於當前的用戶是不可感知的,因爲他現在並沒有立即去查看你的最近通話、短信記錄…

說到這裏,我們自然而然的會想到,其實最好的方式是,當這個應用在用戶使用過程中,正準備使用某個權限時,比如說讀取短信列表,系統能及時的彈出一個提示框,說這個應用要讀取您的短信內容, 您是否允許。然後用戶結合當前應用的執行動作,依據當前條件判斷,是不是應該授予應用讀取短信記錄的權限。這絕對的最完美的。 因爲在具體的使用過程中,用戶可以結合當前應用的使用場景,去思考、判斷是不是應該給這個應用相應的權限。不給能怎樣,給了會怎樣, 這樣對用戶而言,完全是主動的,相比安裝時那種選擇,這樣的做法無疑是對用戶莫大的尊重,同時這也保證了用戶的個人隱私。

說到這裏,不得不插一句,其實 MIUI 早就實現了這個系統特性,在這一點上 MIUI 確實走到了 Android團隊的前面,恩,給 MIUI 點個贊。

然而直到 Android 6.0 這個版本開始,上面的假設終於得到了谷歌的實踐,除了在應用安裝時,操作系統會提示應用會獲取那些權限,在運行過程中,當應用去真的獲取一些敏感 權限時,系統還會彈出一個提示框,詢問用戶是不是授予應用相應的權限。如下圖所示。

這就是 Android 6.0 的運行時權限檢查機制。下面是Google官方對此的解釋,只截取介紹部分

Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen.

解決方案

對Android版本做判斷,然後對Android 6.0 做特殊處理,代碼如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
final public static int REQUEST_CODE_ASK_CALL_PHONE = 123;
 
 public void onCall(String mobile){
        this.mMobile = mobile;
        if (Build.VERSION.SDK_INT >= 23) {
            int checkCallPhonePermission = ContextCompat.checkSelfPermission(mContext,Manifest.permission.CALL_PHONE);
            if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED){
                ActivityCompat.requestPermissions(mContext,new String[]{Manifest.permission.CALL_PHONE},REQUEST_CODE_ASK_CALL_PHONE);
                return;
            }else{
                //上面已經寫好的撥號方法
                callDirectly(mobile);
            }
        else {
            //上面已經寫好的撥號方法
            callDirectly(mobile);
        }
    }

此時,如果一個Android6.0的用戶觸發撥號動作,執行上面的代碼,那麼他將會看到一個很好看的MaterialDialog,如下圖所示。

permission

那麼用戶點擊拒絕或者允許,我們怎麼才能拿到回調呢,如果能拿到回調,我們就可以根據用戶的選擇來執行不同的操作了。

這裏應該會看到在 ActivityCompat 的 requestPermissions 方法中,最後一個參數是一個requestCode,看到它自然而然想到了經常用到的onActivityResult, 這裏當執行 ActivityCompat 的 requestPermissions 方法後有一個回調機制,需要我們在當前 Activity 中實現 onRequestPermissionsResult 這個方法,具體如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE_ASK_CALL_PHONE:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // Permission Granted
                    callDirectly(mobile);
                else {
                    // Permission Denied
                    Toast.makeText(MainActivity.this"CALL_PHONE Denied", Toast.LENGTH_SHORT)
                            .show();
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

這裏會對提供了一個對用戶點擊做判斷的入口,開發者可以根據 grantResults[0] 的類型,來判斷用戶點擊的是允許還是拒絕,接着就可以執行相應的邏輯了。

動態申請權限列表


多個權限的申請,實例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
finalprivate int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124;
 
privatevoid insertDummyContactWrapper() {
    List<String> permissionsNeeded = newArrayList<String>();
 
    finalList<String> permissionsList = newArrayList<String>();
    if(!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
        permissionsNeeded.add("GPS");
    if(!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
        permissionsNeeded.add("Read Contacts");
    if(!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
        permissionsNeeded.add("Write Contacts");
 
    if(permissionsList.size() > 0) {
        if(permissionsNeeded.size() > 0) {
            // Need Rationale
            String message = "You need to grant access to " + permissionsNeeded.get(0);
            for(inti = 1; i < permissionsNeeded.size(); i++)
                message = message + ", " + permissionsNeeded.get(i);
            showMessageOKCancel(message,
                    newDialogInterface.OnClickListener() {
                        @Override
                        publicvoid onClick(DialogInterface dialog, intwhich) {
                            requestPermissions(permissionsList.toArray(newString[permissionsList.size()]),
                                    REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                        }
                    });
            return;
        }
        requestPermissions(permissionsList.toArray(newString[permissionsList.size()]),
                REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
        return;
    }
 
    insertDummyContact();
}
 
privateboolean addPermission(List<String> permissionsList, String permission) {
    if(checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
        permissionsList.add(permission);
        // Check for Rationale Option
        if(!shouldShowRequestPermissionRationale(permission))
            returnfalse;
    }
    returntrue;
}



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override
publicvoid onRequestPermissionsResult(intrequestCode, String[] permissions, int[] grantResults) {
    switch(requestCode) {
        caseREQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
            {
            Map<String, Integer> perms = newHashMap<String, Integer>();
            // Initial
            perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
            perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
            // Fill with results
            for(inti = 0; i < permissions.length; i++)
                perms.put(permissions[i], grantResults[i]);
            // Check for ACCESS_FINE_LOCATION
            if(perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                    && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED
                    && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
                // All Permissions Granted
                insertDummyContact();
            }else{
                // Permission Denied
                Toast.makeText(MainActivity.this,"Some Permission is Denied", Toast.LENGTH_SHORT)
                        .show();
            }
            }
            break;
        default:
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章