Android權限管理之Android 6.0運行時權限及解決辦法

LilianaWhit 8年前發布 | 7K 次閱讀 安卓開發 Android開發 移動開發

前言:

今天還是圍繞著最近面試的一個熱門話題Android 6.0權限適配來總結學習,其實Android 6.0權限適配我們公司是在今年5月份才開始做,算是比較晚的吧,不過現在Android 6.0以上設備越來越多了,所以Android 6.0 權限適配是必不可少的工作,這里主要介紹一下我們公司是如何做Android 6.0權限適配的。

Android 6.0以下非運行時權限:

根據上面博客我們很清楚的知道,Android的權限其實就是為了程序之間更加的安全的訪問,所以權限有等級之分,比如:Normal 低風險權限 、Dangerous  高風險權限等,雖然有這種安全意識,但是這些權限只會在安裝的時候被詢問一次,一旦安裝之后,如果app申請了高風險權限的話,而且大部分用戶在安裝的時候很少去關注這些權限列表,再加上很多Android市場都有靜默安裝的功能用戶更加感知不到任何權限提示,就這樣app就有可能會在后臺做一些對用戶帶來傷害的事情。如下圖所示:

Android6.0運行時權限:

鑒于6.0之前的版本權限管理相對不那么安全,所以Android 6.0 采用新的權限模型,只有在需要權限的時候,才告知用戶是否授權,是在runtime時候授權,而不是在原來安裝的時候 ,同時默認情況下每次在運行時打開頁面時候,需要先檢查是否有所需要的權限申請。這樣的用戶的自主性提高很多,比如用戶可以給APP賦予攝像的權限,也可以使用權限。

Android 6.0權限適配:

1.)不進行適配造成的現象

先看下app module的build.gradle配置

 compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.whoislcj.rxpermissions"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }

由于Android 6.0 以上的權限變成了運行時權限,也就是說在需要使用某個權限的時候必須動態去申請使用,直接訪問直接導致app崩潰。

2.)早期的解決辦法

其實判斷是否是需要運行時權限的標記就是targetSDKVersion,當targetSDKVersion<23的時候,僅在安裝時賦予權限,使用時將不被提醒,當targetSDKVersion≥23的時候才會使用新的運行時權限規則。所有在最早遇見因權限未適配的導致的崩潰的時候,我們團隊采用的解決辦法是將targetSDKVersion人為的降到小于23,這樣就變成了還是默認使用權限,但是這種并不是Google所推薦使用的。

 compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.whoislcj.rxpermissions"
        minSdkVersion 15
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }

3.)判斷是否擁有該權限的使用權限

檢查是否擁有使用權

    public boolean isGranted(String permission) {
        return !isMarshmallow() || isGranted_(permission);
    }

判斷是否是Android 6.0以上

  private boolean isMarshmallow() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

是否申請了該使用權限

 private boolean isGranted_(String permission) {
        int checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission);
        return checkSelfPermission == PackageManager.PERMISSION_GRANTED;
    }

ContextCompat.checkSelfPermission ,主要用于檢測某個權限是否已經被授予,方法返回值為 PackageManager.PERMISSION_DENIED 或者 PackageManager.PERMISSION_GRANTED 。當返回DENIED就需要進行申請授權了。

4.)申請使用權限

    private void requestPermission(String permission, int requestCode) {
        if (!isGranted(permission)) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {

        } else {
            ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
        }
    } else {
        //直接執行相應操作了
    }
}

</code></pre>

shouldShowRequestPermissionRationale主要用于給用戶一個申請權限的解釋,該方法只有在用戶在上一次已經拒絕過你的這個權限申請。也就是說,用戶已經拒絕一次了,你又彈個授權框,你需要給用戶一個解釋,為什么要授權,則使用該方法。requestCode這個需要在處理的回調的時候 一一對應的。

5.)處理授權回調

   @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == CAMERA) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                String jpgPath = getCacheDir() + "test.jpg";
                takePhotoByPath(jpgPath, 2);
            } else {
                // Permission Denied
                Toast.makeText(MainActivity.this, "您沒有授權該權限,請在設置中打開授權", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

6.)完整的Activity示例

public class MainActivity extends AppCompatActivity {
    private static final int CAMERA = 2;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.request_permission).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            requestPermission(Manifest.permission.CAMERA, CAMERA);
        }
    });
}

/**
 * 拍照,返回拍照文件的絕對路徑
 */
private String takePhotoByPath(String filePath, int requestCode) {
    File file = new File(filePath);
    startActivityForResult(getTakePhotoIntent(file), requestCode);
    return file.getPath();
}

private Intent getTakePhotoIntent(File file) {
    if (file.exists()) {
        file.delete();
    }

    try {
        file.createNewFile();
    } catch (IOException e) {
        e.printStackTrace();
    }

    Uri uri = Uri.fromFile(file);
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    return intent;
}

public boolean isGranted(String permission) {
    return !isMarshmallow() || isGranted_(permission);
}

private boolean isGranted_(String permission) {
    int checkSelfPermission = ActivityCompat.checkSelfPermission(this, permission);
    return checkSelfPermission == PackageManager.PERMISSION_GRANTED;
}

private boolean isMarshmallow() {
    return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}

//shouldShowRequestPermissionRationale主要用于給用戶一個申請權限的解釋,該方法只有在用戶在上一次已經拒絕過你的這個權限申請。也就是說,用戶已經拒絕一次了,你又彈個授權框,你需要給用戶一個解釋,為什么要授權,則使用該方法。
private void requestPermission(String permission, int requestCode) {
    if (!isGranted(permission)) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {

        } else {
            ActivityCompat.requestPermissions(this, new String[]{permission}, requestCode);
        }
    } else {
        //直接執行相應操作了
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    if (requestCode == CAMERA) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            String jpgPath = getCacheDir() + "test.jpg";
            takePhotoByPath(jpgPath, 2);
        } else {
            // Permission Denied
            Toast.makeText(MainActivity.this, "您沒有授權該權限,請在設置中打開授權", Toast.LENGTH_SHORT).show();
        }
        return;
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

} </code></pre>

總結:

本篇總結學習了Android 6.0的運行時權限及如何適配的問題,但是這個并不是我們公司目前最終的解決辦法,從上面可以看出實現起來還是蠻麻煩的,申請權限和處理回調在不同的地方代碼可讀性相對較差,我們最終的解決方案是采用RxJava+RxPermission的方式解決,下一篇將介紹一下如何使用RxPermission解決Android 6.0 權限適配問題。

 

來自:http://www.cnblogs.com/whoislcj/p/6064710.html

 

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