標籤:developer blog des 申請 技術分享 back net lis ntc
前言
android6.0開始,許可權的申請發生了改變,申請變的動態化,也就是執行時許可權,和iOS相仿,動態化的意思是指,在每次使用須要危急許可權的方法的時候。須要檢查程式是否獲得了該許可權的許可。動態化的許可權申請能夠讓使用者更加清晰的知道程式須要什麼許可權。以及程式中哪些地方的操作須要涉及使用者安全。
不再是只在程式安裝的時候,一次性把所須要的普通的、危急層級的許可權一次性列出來。然後展示給使用者。
當project項目的target Sdk為23時,因為考慮到使用者假設沒有進行許可權的動態檢查,那麼在執行到須要許可權的代碼時,會發生crash。而當你的target Sdk為23下面時,則不強制要求許可權的動態監測,此時app不會crash。還是能夠正常的使用功能。
Google官網上動態申請許可權的方法分了在Activity和Fragment這兩種,通過ContextCompat以及子類,ActivityCompat和FragmentCompat去進行許可權的申請和許可權的檢查,而申請的方式是彈出一個系統的不能夠改寫的對話方塊。結果是通過Activity和Fragment的onRequestPermissionResult()方法進行返回。
詳細能夠參考官網
可是這樣的代碼會促使以前的project進行大改造或者說代碼的邏輯會耦合的寫在同一個方法裡。顯的不方便和臃腫。
所以下面的EasyPermissionUtil就是簡化許可權請求的方式,同一時候能夠使代碼的邏輯更加清晰。
EasyPermissionUtil:簡化許可權請求
因為許可權的請求和結果的返回須要分開Activity和Fragment兩種去進行操作,這樣會比較麻煩,所以EasyPermissionUtil中投機取巧,通過開啟一個新的activity進行許可權申請和檢查的操作。這樣不用去區分多種情況,同一時候也能夠把全部的申請過程和結果統一由EasyPermissionUtil進行處理。
接下來看一下總體的思想:
使用的方法
PermissionUtil.getInstance().request(MainActivity.this, new String[]{Manifest.permission.READ_CALENDAR}, mRequestCode, new PermissionResultCallBack() { @Override public void onPermissionGranted() { // 當全部許可權的申請被使用者允許之後,該方法會被調用 } @Override public void onPermissionDenied(String... permissions) { // 當許可權申請中的某一個或多個許可權,被使用者以前否定了,並確認了不再提醒時,也就是許可權的申請表單不能再彈出時,該方法將會被調用 } @Override public void onRationalShow(String... permissions) { // 當許可權申請中的某一個或多個許可權,被使用者否定了,但沒有確認不再提醒時,也就是許可權表單申請時,但被否定了之後,該方法將會被調用. } });
項目原始碼下載以及介紹。請看github。
項目原始碼
在PermissionUtil中,要做的是:
1.進行許可權檢查
2.沒有得到許可權許可的進行許可權申請
3.返回許可權申請的結果
public class PermissionUtil { private PermissionResultCallBack mPermissionResultCallBack; private volatile static PermissionUtil instance; private int mRequestCode; private Context mContext; private Fragment mFragment; private List<PermissionInfo> mPermissionListNeedReq; private String[] mPermissions; public static PermissionUtil getInstance() { if (instance == null) { synchronized (PermissionUtil.class) { if (instance == null) { instance = new PermissionUtil(); } } } return instance; } /** * 用於fragment中請求許可權 * @param fragment * @param permissions * @param requestCode * @param callBack */ public void request(@NonNull Fragment fragment,@NonNull String[] permissions,@NonNull int requestCode, PermissionResultCallBack callBack) { this.mFragment = fragment; this.request(fragment.getActivity(), permissions, requestCode, callBack); } /** * 用於activity中請求許可權 * @param context * @param permissions * @param requestCode * @param callBack */ public void request(@NonNull Context context,@NonNull String[] permissions,@NonNull int requestCode, PermissionResultCallBack callBack) { if (Looper.myLooper() != Looper.getMainLooper()) { throw new RuntimeException("request permission only can run in MainThread!"); } if (permissions.length == 0) { return; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { onGranted(); return; } this.mContext = context; this.mPermissions = permissions; this.mRequestCode = requestCode; this.mPermissionResultCallBack = callBack; this.mPermissionListNeedReq = new ArrayList<PermissionInfo>(); if (needToRequest()) { requestPermissions(); } else { onGranted(); } } /** * 通過開啟一個新的activity作為申請許可權的媒介 */ private void requestPermissions() { Intent intent = new Intent(mContext, HelpActivity.class); intent.putExtra("permissions", mPermissions); intent.putExtra("requestCode", mRequestCode); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(intent); } /** * 檢查是否須要申請許可權 * @return */ private boolean needToRequest() { for (String permission : mPermissions) { int checkRes = ContextCompat.checkSelfPermission(mContext, permission); if (checkRes != PackageManager.PERMISSION_GRANTED) { PermissionInfo info = new PermissionInfo(permission); if (mContext instanceof Activity && ActivityCompat.shouldShowRequestPermissionRationale((Activity) mContext, permission)) { info.setRationalNeed(true); } mPermissionListNeedReq.add(info); } } if (mPermissionListNeedReq.size() > 0) { mPermissions = new String[mPermissionListNeedReq.size()]; for (int i = 0; i < mPermissionListNeedReq.size(); i++) { mPermissions[i] = mPermissionListNeedReq.get(i).getName(); } return true; } return false; } /** * 申請許可權結果返回 * @param requestCode * @param permissions * @param grantResults */ @TargetApi(Build.VERSION_CODES.M) protected void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == mRequestCode) { if (mContext != null && mContext instanceof Activity) { ((Activity) mContext).onRequestPermissionsResult(requestCode, permissions, grantResults); } if (mFragment != null) { mFragment.onRequestPermissionsResult(requestCode, permissions, grantResults); } boolean isAllGranted = true; List<PermissionInfo> needRationalPermissionList = new ArrayList<PermissionInfo>(); List<PermissionInfo> deniedPermissionList = new ArrayList<PermissionInfo>(); for (int i = 0; i < permissions.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { if (mPermissionListNeedReq.get(i).isRationalNeed()) { needRationalPermissionList.add(mPermissionListNeedReq.get(i)); } else { deniedPermissionList.add(mPermissionListNeedReq.get(i)); } isAllGranted = false; } } if (needRationalPermissionList.size() != 0) { showRational(needRationalPermissionList); } if (deniedPermissionList.size() != 0) { onDenied(deniedPermissionList); } if (isAllGranted) { onGranted(); } } } /** * 許可權被使用者許可之後回調的方法 */ private void onGranted() { if (mPermissionResultCallBack != null) { mPermissionResultCallBack.onPermissionGranted(); } } /** * 許可權申請被使用者否定之後的回調方法,這個主要是當使用者點擊否定的同一時候點擊了不在彈出, * 那麼當再次申請許可權,此方法會被調用 * @param list */ private void onDenied(List<PermissionInfo> list) { if(list == null || list.size() == 0) return; String[] permissions = new String[list.size()]; for (int i = 0; i < list.size(); i++) { permissions[i] = list.get(i).getName(); } if (mPermissionResultCallBack != null) { mPermissionResultCallBack.onPermissionDenied(permissions); } } /** * 許可權申請被使用者否定後的回調方法,這個主要情境是當使用者點擊了否定,但未點擊不在彈出, * 那麼當再次申請許可權的時候,此方法會被調用 * @param list */ private void showRational(List<PermissionInfo> list) { if(list == null || list.size() == 0) return; String[] permissions = new String[list.size()]; for (int i = 0; i < list.size(); i++) { permissions[i] = list.get(i).getName(); } if (mPermissionResultCallBack != null) { mPermissionResultCallBack.onRationalShow(permissions); } }}
在PermissionResutCallBack中,要做的是:
1.返回相應的結果
public interface PermissionResultCallBack { /** * 當全部許可權的申請被使用者允許之後,該方法會被調用 */ void onPermissionGranted(); /** * 當許可權申請中的某一個或多個許可權,被使用者以前否定了,並確認了不再提醒時,也就是許可權的申請表單不能再彈出時, * 該方法將會被調用 * @param permissions */ void onPermissionDenied(String... permissions); /** * 當許可權申請中的某一個或多個許可權,被使用者否定了,但沒有確認不再提醒時,也就是許可權表單申請時,但被否定了之後, * 該方法將會被調用. * @param permissions */ void onRationalShow(String... permissions);}
在HelpActivity中。要做的就是:
1.申請許可權
2.通過onRequestPermissionUtil返回結果給PermissionUtil
當然這個activity必須是透明的,並且是沒有不論什麼的view的。這樣看起來才不像是開了一個新的activity。
public class HelpActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { handleIntent(getIntent()); } } @Override protected void onNewIntent(Intent intent) { handleIntent(intent); } // 許可權申請 @TargetApi(Build.VERSION_CODES.M) private void handleIntent(Intent intent) { String[] permissions = intent.getStringArrayExtra("permissions"); int requestCode = intent.getIntExtra("requestCode", 42); ActivityCompat.requestPermissions(this, permissions, requestCode); } @Override protected void onDestroy() { super.onDestroy(); } // 返回結果 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { PermissionUtil.getInstance().onRequestPermissionResult(requestCode, permissions, grantResults); finish(); }}
項目原始碼下載以及介紹。請看github。
android6.0許可權管理工具EasyPermissionUtil