Android 6.0版本(Api 23)推出了不少新的特性, 大幅提高了用戶體驗, 同時也爲程序員帶來新的負擔. 動態權限管理就是這樣, 一方面讓用戶更加容易的控制本身的隱私, 一方面須要從新適配應用權限. 時代老是不斷髮展, 程序老是以人爲本, 讓咱們爲應用添加動態權限管理吧! 這裏提供了一個很是不錯的解決方案, 提供源碼, 項目能夠直接使用.java
Permissionsandroid
Android系統包含默認的受權提示框, 可是咱們仍須要設置本身的頁面. 緣由是系統提供的受權框, 會有再也不提示的選項. 若是用戶選擇, 則沒法觸發受權提示. 使用自定義的提示頁面, 能夠給予用戶手動修改受權的指導.git
本文示例的GitHub下載地址程序員
在Api 23中, 權限須要動態獲取, 核心權限必須知足. 標準流程:github
流程圖ide
若是用戶點擊, 再也不提示, 則系統受權彈窗將不會彈出. 流程變爲:工具
流程圖ui
流程就這些, 讓咱們看看代碼吧.this
在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; } }
假設首頁須要使用權限, 在頁面顯示前, 即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(); } } }
核心權限必須知足, 如攝像應用, 攝像頭權限就是必須的, 若是用戶不予受權, 則直接關閉.
受權頁, 首先使用系統默認的受權頁, 當用戶拒絕時, 指導用戶手動設置, 當用戶再次操做失敗後, 返回繼續提示. 用戶手動退出受權頁時, 給使用頁發送受權失敗的通知.
/** * 權限獲取頁面 * <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著做權歸做者全部,轉載請聯繫做者得到受權,並標註「簡書做者」。