淺談Android 6.0之Runtime Permissions

naryn 8年前發布 | 20K 次閱讀 Android開發 移動開發 Android

前言

Android6.0發布后,其一系列新特新足夠讓我們這些Android程序員興奮一段時間了。首先我們先看看具體有哪些新特性:

-鎖頻下語音搜索
-指紋識別
-更完整的應用權限管理
-Doze電量管理
-Now on Tap
-App link

具體可以參考Android 6.0有哪些新特性

上面六個新特性中更完整的應用權限管理應該是和我們開發者關系最密切的了,接下來我們就來具體了解一下如何在Android 6.0上更好的使用Android系統權限。

Runtime Permissions

在Android 6.0中谷歌摒棄了之前的install time permissions model取而代之的是runtime permissions model。先來說說install time permissions model,這個大家不陌生,就是當Android App安裝的時候會向用戶展示一坨權限,如果此時用戶選擇安裝,則表示用戶同意將這些權限賦予App,如果用戶不同意那么這個App就會取消安裝。runtime permissions model就牛逼了,在App安裝的時候同樣會向用戶展示所需要的權限,并且在用戶選擇安裝App的時候并不表示用戶將這些權限賦予了App,而是需要App在運行階段主動去申請這些權限。這樣做的好處顯而易見,App對權限的申請對于用戶來說變得更加透明,而且用戶對App權限的控制也更加靈活。

權限的分類

Android將系統權限分成了四個保護等級normal,dangerous,signature,signatureOrSystem,其中最常見的是normal permissiondangerous permission兩類。

normal permission涵蓋的一系列權限的共同點是:App需要訪問App運行沙盒以外的數據或資源,但是這些資源對用戶的隱私或其他App的危險性較小,下面列舉一下這些權限:

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
FLASHLIGHT
GET_PACKAGE_SIZE
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
SET_ALARM
INSTALL_SHORTCUT

以上這些就是Android 6.0中所有的normal permissions了。

dangerous permissions 涵蓋的一系列權限的共同點是:這些權限會讀寫用戶的隱私信息,也可能會讀寫用戶存儲的數據或影響其他App的正常運行。下面例舉出這些權限:
| 權限組| 權限|
|------------------|--------------------------------------------------------------------------------------------------------------|
|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 |
以上這些權限就是Android6.0中所有的dangerous permissions

Runtime Permissions針對的是dangerous permissionsnormal permissions還是會在App安裝期間被默認賦予。

實戰

下面我們就以STORAGE組中的WRITE_EXTERNAL_STORAGE為例子,嘗試在Android 6.0中使用runtime permission相關api。
我們要做的事情非常簡單,在手機的存儲設備上新建一個hello.txt。

1.在AndroidManifest文件中添加如下權限生命

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

2.在MainActivity中添加如下方法:

    //在sdcard上新建一個名為fileName的文件
    private void createFile(String fileName){
        File sdcard = Environment.getExternalStorageDirectory();
        File newFile = new File(sdcard,"/" + fileName) ;
        if(!newFile.exists()){
            try {
                newFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

好的,如果沒有runtime permissions這個概念的話,那其實這個功能已經完成了,我們來看看它在Android 6.0之前的版本上的運行情況,

首先是安裝時的界面:

這里寫圖片描述

它提示用戶該應用會修改會刪除SD卡的內容,如果此時用戶選擇安裝,那么也就是默認將WRITE_EXTERNAL_STORAGE這個權限賦予了該應用。

再來看運行結果:

這里寫圖片描述

看吧,文件直接就創建成功了,這樣真的是很危險的。

接下來再在Android6.0的機子上安裝這個應用,安裝截圖如下:

這里寫圖片描述

這個安裝界面和之前的一樣,也是向用戶展示了App所涉及的權限。

下面看運行結果:

這里寫圖片描述

這里就出問題了,log顯示App沒有權限在SD卡上創建文件。這里要再講一下runtime permissions原理

對于權限分類中的dangerous permissions,runtime permissions要求App在運行的時候做權限請求,某則App則無法獲得相應請求。

接下來看一下怎么在代碼中進行權限的申請:


    public static final int EXTERNAL_STORAGE_REQ_CODE = 10 ;

public void requestPermission(){
    //判斷當前Activity是否已經獲得了該權限
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {

        //如果App的權限申請曾經被用戶拒絕過,就需要在這里跟用戶做出解釋
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            Toast.makeText(this,"please give me the permission",Toast.LENGTH_SHORT).show();
        } else {
            //進行權限請求
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    EXTERNAL_STORAGE_REQ_CODE);
        }
    }
}</code></pre> 

當進行權限申請,并且用戶做出選擇后會回調onRequestPermissionsResult這個方法,在這個方法中做相關處理

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case EXTERNAL_STORAGE_REQ_CODE: {
                // 如果請求被拒絕,那么通常grantResults數組為空
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    //申請成功,進行相應操作
                    createFile("hello.txt");
                } else {
                    //申請失敗,可以繼續向用戶解釋。
                }
                return;
            }
        }
    }

到這里runtime permissions的權限申請操作就結束了,我們看一下效果:

這里寫圖片描述

允許后會再次調用createFile("hello.txt")方法,這次文件會被成功創建。

這里寫圖片描述

總結

其實還有一些內容需要寫,這里先//TODO一下,希望以上內容對你有所幫助。

 

 本文由用戶 naryn 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!