Andorid的權(quán)限控制

概述

默認(rèn)情況下,Android應(yīng)用程序是沒有任何授權(quán)的,當(dāng)應(yīng)用程序需要使用設(shè)備的任何受保護(hù)功能(發(fā)送網(wǎng)絡(luò)請求,訪問攝像機(jī),發(fā)送短信等)時,必須從用戶那里獲得相應(yīng)的權(quán)限。

在Marshmallow之前,權(quán)限都在安裝時在項(xiàng)目中的清單文件中定義。在Marshmallow之后,現(xiàn)在必須在運(yùn)行時請求權(quán)限,然后才能使用。PermissionsDispatcher第三方庫用于管理運(yùn)行時權(quán)限。

Marshmallow之前的權(quán)限控制

當(dāng)用戶從Google Play商店安裝應(yīng)用程序時,系統(tǒng)會向用戶顯示該應(yīng)用程序所需的權(quán)限列表(有些人將此稱為“權(quán)限墻”),用戶可以接受所有權(quán)限,然后繼續(xù)安裝應(yīng)用程序或決定不安裝應(yīng)用程序。沒有辦法只授予該應(yīng)用程序的某些權(quán)限,用戶沒有辦法撤消在安裝應(yīng)用程序后的某些權(quán)限。

關(guān)于系統(tǒng)的權(quán)限列表:permissions

Marshmallow之后的權(quán)限控制

Marshmallow引入了運(yùn)行時權(quán)限的概念,意味著你的targetSdkVersion<23的話需要做兼容性處理。

當(dāng)你需要添加新權(quán)限時,請先檢查是否屬于PROTECTION_NORMAL
。在Marshmallow中,Google已將某些權(quán)限指定為“安全”,并稱為“常規(guī)權(quán)限”。 這些東西,比如ACCESS_NETWORK_STATE,INTERNET等。 在安裝時自動授予常規(guī)權(quán)限,并且不會提示用戶請求權(quán)限。

常規(guī)權(quán)限必須在清單文件中定義:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.app.myapp" >
    
    <uses-permission android:name="android.permission.INTERNET" />
    ...
</manifest>

運(yùn)行時權(quán)限

這類權(quán)限將向用戶顯示一個對話框,類似于以下:


runtime-permission.png
  1. 將運(yùn)行時權(quán)限添加到清單文件中:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.codepath.androidpermissionsdemo" >

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    ...
</manifest>
  1. 你需要使用android.support.v4.app.ActivityCompat這個向系統(tǒng)申請權(quán)限的工具類,兼容了各種系統(tǒng)版本。如下:
  • ActivityCompat.requestPermissions向系統(tǒng)申請一個或一組權(quán) 限
  • ActivityCompat.checkSelfPermissionApp檢查自己是否有某個權(quán)限
  • ActivityCompat.shouldShowRequestPermissionRationale判斷彈出對話框中是否含有“不再詢問”的選擇框

步驟

  1. 你要有一個運(yùn)行Android 6.0系統(tǒng)的設(shè)備
  2. 將App的targetSdkVersion設(shè)置為23
  3. 把AndroidManifest.xml中申請的并且是危險(xiǎn)的所有權(quán)限都列出來,用ActivityCompat.requestPermissions方法向系統(tǒng)申請權(quán)限
  4. 在所在的Activity中OverrideonRequestPermissionsResult方法接受系統(tǒng)權(quán)限申請的回調(diào)
  5. 處理回調(diào),比如用戶拒絕了某個權(quán)限,這時App可以彈出一個對話框描述一下App為何需要這個權(quán)限等等
// MainActivity.java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        // In an actual app, you'd want to request a permission when the user performs an action
        // that requires that permission.
        getPermissionToReadUserContacts();
    }

    // Identifier for the permission request
    private static final int READ_CONTACTS_PERMISSIONS_REQUEST = 1;

    // Called when the user is performing an action which requires the app to read the
    // user's contacts
    public void getPermissionToReadUserContacts() {
        // 1) Use the support library version ContextCompat.checkSelfPermission(...) to avoid
        // checking the build version since Context.checkSelfPermission(...) is only available
        // in Marshmallow
        // 2) Always check for permission (even if permission has already been granted)
        // since the user can revoke permissions at any time through Settings
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {

            // The permission is NOT already granted.
            // Check if the user has been asked about this permission already and denied
            // it. If so, we want to give more explanation about why the permission is needed.
            if (shouldShowRequestPermissionRationale(
                    Manifest.permission.READ_CONTACTS)) {
                // Show our own UI to explain to the user why we need to read the contacts
                // before actually requesting the permission and showing the default UI
            }

            // Fire off an async request to actually get the permission
            // This will show the standard permission request dialog UI
            requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
                    READ_CONTACTS_PERMISSIONS_REQUEST);
        }
    }

    // Callback with the request from calling requestPermissions(...)
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String permissions[],
                                           @NonNull int[] grantResults) {
        // Make sure it's our original READ_CONTACTS request
        if (requestCode == READ_CONTACTS_PERMISSIONS_REQUEST) {
            if (grantResults.length == 1 &&
                    grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "Read Contacts permission granted", Toast.LENGTH_SHORT).show();
            } else {
                // showRationale = false if user clicks Never Ask Again, otherwise true
                boolean showRationale = shouldShowRequestPermissionRationale( this, Manifest.permission.READ_CONTACTS);

                if (showRationale) {
                   // do something here to handle degraded mode
                } else {
                   Toast.makeText(this, "Read Contacts permission denied", Toast.LENGTH_SHORT).show();
                }
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
}

權(quán)限組

相關(guān)權(quán)限分組到一個權(quán)限組。 當(dāng)應(yīng)用請求屬于特定權(quán)限組(即READ_CONTACTS)的權(quán)限時,Android會向用戶詢問更高級別的組(CONTACTS)。 這樣,當(dāng)應(yīng)用程序稍后需要WRITE_CONTACTS權(quán)限時,Android可以自動授予此權(quán)限,而不會提示用戶。

group-permission.png

向后兼容

  1. 你的App指定的targetSdkVersion<23,不過你的設(shè)備或者模擬器是Marshmallow
    • 你的app會繼續(xù)使用舊的權(quán)限模型
    • 將在安裝時詢問AndroidManifest中列出的所有權(quán)限。
    • 用戶將能夠在安裝應(yīng)用程序后撤消權(quán)限
    • 使用PermissionChecker.checkSelfPermission方法檢查App自身有沒有某一個權(quán)限,這個方法的返回結(jié)果只有三種:
      • PERMISSION_GRANTED: 已授權(quán)
      • PERMISSION_DENIED: 沒有被授權(quán)
      • PERMISSION_DENIED_APP_OP: 沒有被授權(quán)(如果targetSdkVersion小于23)
  2. 你的App指定的targetSdkVersion>=23,不過你的設(shè)備或者模擬器低于Marshmallow
    • 你的app會繼續(xù)使用舊的權(quán)限模型
    • 將在安裝時詢問AndroidManifest中列出的所有權(quán)限。
    • 使用context.checkSelfPermission(permission)方法檢查App自身有沒有某一個權(quán)限。
try {
    final PackageInfo info = context.getPackageManager().getPackageInfo(
        context.getPackageName(), 0);
    targetSdkVersion = info.applicationInfo.targetSdkVersion;
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

public boolean selfPermissionGranted(Context context, String permission) {
    // Android 6.0 以前,全部默認(rèn)授權(quán)
    boolean result = true;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
       if (targetSdkVersion >= Build.VERSION_CODES.M) {
            // targetSdkVersion >= 23, 使用Context#checkSelfPermission
            result = context.checkSelfPermission(permission)
                    == PackageManager.PERMISSION_GRANTED;
        } else {
            // targetSdkVersion < 23, 需要使用 PermissionChecker
            result = PermissionChecker.checkSelfPermission(context, permission)
                    == PermissionChecker.PERMISSION_GRANTED;
        }
    }
    return result;
}

存儲權(quán)限

重新思考您是否需要讀取/寫入存儲權(quán)限(即android.permission.WRITE_EXTERNAL_STORAGE或android.permission.READ_EXTERNAL_STORAGE),它會為您提供SD卡上的所有文件。 相反,您應(yīng)該使用Context上的方法來訪問外部存儲上特定于軟件包的目錄。 您的應(yīng)用程序始終可以訪問對這些目錄的讀/寫,因此無需請求權(quán)限:

// Application-specific call that doesn't require external storage permissions
// Can be Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_PODCASTS, Environment.DIRECTORY_RINGTONES, 
// Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_PICTURES, or Environment.MOVIES
File dir = MyActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容