android 6.0 動態權限管理的解決方案

Android 6.0版本(Api 23)推出了不少新的特性, 大幅提高了用戶體驗, 同時也爲程序員帶來新的負擔. 動態權限管理就是這樣, 一方面讓用戶更加容易的控制本身的隱私, 一方面須要從新適配應用權限. 時代老是不斷髮展, 程序老是以人爲本, 讓咱們爲應用添加動態權限管理吧! 這裏提供了一個很是不錯的解決方案, 提供源碼, 項目能夠直接使用.java


Permissionsandroid

Android系統包含默認的受權提示框, 可是咱們仍須要設置本身的頁面. 緣由是系統提供的受權框, 會有再也不提示的選項. 若是用戶選擇, 則沒法觸發受權提示. 使用自定義的提示頁面, 能夠給予用戶手動修改受權的指導.git

本文示例的GitHub下載地址程序員

在Api 23中, 權限須要動態獲取, 核心權限必須知足. 標準流程:github


流程圖ide

若是用戶點擊, 再也不提示, 則系統受權彈窗將不會彈出. 流程變爲:工具


流程圖ui

流程就這些, 讓咱們看看代碼吧.this


1. 權限

在AndroidManifest中, 添加兩個權限, 錄音修改音量.code

    <!--危險權限-->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

    <!--通常權限-->
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

危險權限必需要受權, 通常權限不須要.

檢測權限類

/**
 * 檢查權限的工具類
 * <p/>
 * Created by wangchenlong on 16/1/26.
 */public class PermissionsChecker {    private final Context mContext;    public PermissionsChecker(Context context) {
        mContext = context.getApplicationContext();
    }    // 判斷權限集合
    public boolean lacksPermissions(String... permissions) {        for (String permission : permissions) {            if (lacksPermission(permission)) {                return true;
            }
        }        return false;
    }    // 判斷是否缺乏權限
    private boolean lacksPermission(String permission) {        return ContextCompat.checkSelfPermission(mContext, permission) ==
                PackageManager.PERMISSION_DENIED;
    }
}

2. 首頁

假設首頁須要使用權限, 在頁面顯示前, 即onResume時, 檢測權限,
若是缺乏, 則進入權限獲取頁面; 接收返回值, 拒絕權限時, 直接關閉.

public class MainActivity extends AppCompatActivity {    private static final int REQUEST_CODE = 0; // 請求碼

    // 所需的所有權限
    static final String[] PERMISSIONS = new String[]{
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.MODIFY_AUDIO_SETTINGS
    };    @Bind(R.id.main_t_toolbar) Toolbar mTToolbar;    private PermissionsChecker mPermissionsChecker; // 權限檢測器

    @Override
    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        setSupportActionBar(mTToolbar);

        mPermissionsChecker = new PermissionsChecker(this);
    }    @Override protected void onResume() {        super.onResume();        // 缺乏權限時, 進入權限配置頁面
        if (mPermissionsChecker.lacksPermissions(PERMISSIONS)) {
            startPermissionsActivity();
        }
    }    private void startPermissionsActivity() {
        PermissionsActivity.startActivityForResult(this, REQUEST_CODE, PERMISSIONS);
    }    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        // 拒絕時, 關閉頁面, 缺乏主要權限, 沒法運行
        if (requestCode == REQUEST_CODE && resultCode == PermissionsActivity.PERMISSIONS_DENIED) {
            finish();
        }
    }
}

核心權限必須知足, 如攝像應用, 攝像頭權限就是必須的, 若是用戶不予受權, 則直接關閉.


3. 受權頁

受權頁, 首先使用系統默認的受權頁, 當用戶拒絕時, 指導用戶手動設置, 當用戶再次操做失敗後, 返回繼續提示. 用戶手動退出受權頁時, 給使用頁發送受權失敗的通知.

/**
 * 權限獲取頁面
 * <p/>
 * Created by wangchenlong on 16/1/26.
 */public class PermissionsActivity extends AppCompatActivity {    public static final int PERMISSIONS_GRANTED = 0; // 權限受權
    public static final int PERMISSIONS_DENIED = 1; // 權限拒絕

    private static final int PERMISSION_REQUEST_CODE = 0; // 系統權限管理頁面的參數
    private static final String EXTRA_PERMISSIONS =            "me.chunyu.clwang.permission.extra_permission"; // 權限參數
    private static final String PACKAGE_URL_SCHEME = "package:"; // 方案

    private PermissionsChecker mChecker; // 權限檢測器
    private boolean isRequireCheck; // 是否須要系統權限檢測

    // 啓動當前權限頁面的公開接口
    public static void startActivityForResult(Activity activity, int requestCode, String... permissions) {
        Intent intent = new Intent(activity, PermissionsActivity.class);
        intent.putExtra(EXTRA_PERMISSIONS, permissions);
        ActivityCompat.startActivityForResult(activity, intent, requestCode, null);
    }    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        if (getIntent() == null || !getIntent().hasExtra(EXTRA_PERMISSIONS)) {            throw new RuntimeException("PermissionsActivity須要使用靜態startActivityForResult方法啓動!");
        }
        setContentView(R.layout.activity_permissions);

        mChecker = new PermissionsChecker(this);
        isRequireCheck = true;
    }    @Override protected void onResume() {        super.onResume();        if (isRequireCheck) {
            String[] permissions = getPermissions();            if (mChecker.lacksPermissions(permissions)) {
                requestPermissions(permissions); // 請求權限
            } else {
                allPermissionsGranted(); // 所有權限都已獲取
            }
        } else {
            isRequireCheck = true;
        }
    }    // 返回傳遞的權限參數
    private String[] getPermissions() {        return getIntent().getStringArrayExtra(EXTRA_PERMISSIONS);
    }    // 請求權限兼容低版本
    private void requestPermissions(String... permissions) {
        ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
    }    // 所有權限均已獲取
    private void allPermissionsGranted() {
        setResult(PERMISSIONS_GRANTED);
        finish();
    }    /**
     * 用戶權限處理,
     * 若是所有獲取, 則直接過.
     * 若是權限缺失, 則提示Dialog.
     *
     * @param requestCode  請求碼
     * @param permissions  權限
     * @param grantResults 結果
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        if (requestCode == PERMISSION_REQUEST_CODE && hasAllPermissionsGranted(grantResults)) {
            isRequireCheck = true;
            allPermissionsGranted();
        } else {
            isRequireCheck = false;
            showMissingPermissionDialog();
        }
    }    // 含有所有的權限
    private boolean hasAllPermissionsGranted(@NonNull int[] grantResults) {        for (int grantResult : grantResults) {            if (grantResult == PackageManager.PERMISSION_DENIED) {                return false;
            }
        }        return true;
    }    // 顯示缺失權限提示
    private void showMissingPermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(PermissionsActivity.this);
        builder.setTitle(R.string.help);
        builder.setMessage(R.string.string_help_text);        // 拒絕, 退出應用
        builder.setNegativeButton(R.string.quit, new DialogInterface.OnClickListener() {            @Override public void onClick(DialogInterface dialog, int which) {
                setResult(PERMISSIONS_DENIED);
                finish();
            }
        });

        builder.setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() {            @Override public void onClick(DialogInterface dialog, int which) {
                startAppSettings();
            }
        });

        builder.show();
    }    // 啓動應用的設置
    private void startAppSettings() {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse(PACKAGE_URL_SCHEME + getPackageName()));
        startActivity(intent);
    }
}

注意isRequireCheck參數的使用, 防止和系統提示框重疊.
系統受權提示: ActivityCompat.requestPermissions, ActivityCompat兼容低版本.

效果


自定義受權


關鍵部分就這些了, 動態權限受權雖然給程序員帶來了一些麻煩, 可是對用戶仍是頗有必要的, 咱們也應該歡迎, 畢竟每一個程序員都是半個產品經理.

危險權限列表


危險權限列表



文/SpikeKing(簡書做者)原文連接:http://www.jianshu.com/p/dbe4d37731e6著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。

相關文章
相關標籤/搜索