寫在前面
上次寫了一個權限申請的例子Android 6.0 超級簡單的權限申請 (Permission),原理是封裝權限申請的代碼到一個Helper類,然后重寫onRequestPermissionsResult
方法處理。這已經是很簡潔的權限申請方法了,但是還不夠,因為這里還需要重寫onRequestPermissionsResult
方法。所以研究了一番,再寫了一個例子,不需要重寫onRequestPermissionsResult
方法,真正做到一句代碼搞定權限申請。
實現原理
封裝權限申請的相關代碼到一個Helper類中,在申請權限的時候,啟動一個Fragment,但不顯示,在Fragment中申請權限,也在Fragment中處理權限,最后回調給Helper。
實現過程
- 封裝
PermissionHelper
類,定義對外開放的方法
/**
* @param permissions e.g. {@link Manifest.permission#CAMERA}
* @return true if all granted, false otherwise.
*/
public static boolean isGranted(Activity activity, String... permissions)
/**
* @param grantedListener run on all permission granted
* @param deniedListener run if one permission denied
*/
public static void requestPermissions(Activity activity,
OnPermissionGrantedListener grantedListener,
OnPermissionDeniedListener deniedListener,
String... permissions)
- 獲取
AndroidManifest
中注冊的權限
private static List<String> getRegisteredInManifestPermissions(Activity activity) {
List<String> list = new ArrayList<>();
try {
PackageInfo packageInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS);
String[] permissions = packageInfo.requestedPermissions;
if (permissions != null) {
list.addAll(Arrays.asList(permissions));
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return list;
}
- 檢查權限是否已經注冊
for (String permission : permissions) {
if (!mRegisteredInManifestPermissions.contains(permission)) {
throw new IllegalArgumentException("the permission \"" + permission + "\" is not registered in AndroidManifest.xml");
}
}
- 檢查權限是否已經允許,AndroidM以下的設備直接判斷為允許
public static boolean isGranted(Activity activity, String... permissions) {
checkPermissions(activity, permissions);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String permission : permissions) {
if (activity.checkSelfPermission(permission) == PackageManager.PERMISSION_DENIED) {
return false;
}
}
}
return true;
}
- 初始化
Fragment
並添加到Activity
中
這里的PermissionHelper
直接繼承Fragment
了,直接重寫onRequestPermissionsResult
處理回調。new Fragment
之前先檢查此Activity中是否已經存在一個,如果有則直接使用。
Fragment fragment = activity.getFragmentManager().findFragmentByTag(TAG);
if (fragment == null) {
fragment = new PermissionHelper();
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager.beginTransaction().add(fragment, TAG).commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
- 利用Fragment申請權限
fragment.requestPermissions(permissions, mRequestCode++);
- 處理
onRequestPermissionsResult
方法,並把結果正確的回調給用戶
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (mOnGrantedListeners.containsKey(requestCode)) {
// 這里規定全部權限都通過才算通過
boolean granted = true;
// 在Activity A申請權限,然后馬上跳轉到Activity B,則grantResults.length=0
if (grantResults.length == 0) granted = false;
for (int result : grantResults) {
if (result == PackageManager.PERMISSION_DENIED) {
granted = false;
}
}
if (granted) {
OnPermissionGrantedListener listener = mOnGrantedListeners.get(requestCode);
if (listener != null) listener.onGranted();
} else {
OnPermissionDeniedListener listener = mOnDeniedListeners.get(requestCode);
if (listener != null) listener.onDenied();
}
mOnGrantedListeners.remove(mRequestCode);
mOnDeniedListeners.remove(mRequestCode);
}
}
使用方法
直接在Activity中調用下面代碼既可,雖然很多行,但只是一句代碼哈哈
PermissionHelper.requestPermissions(this, () -> {
// on granted
Toast.makeText(MainActivity.this, "onGranted", Toast.LENGTH_SHORT).show();
}, () -> {
// on denied
Toast.makeText(MainActivity.this, "onDenied", Toast.LENGTH_SHORT).show();
}, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE);
文件結構圖
演示效果圖
運行代碼可能出現的問題
-
compileSdkVersion 27,可以改成你電腦中存在的SDK版本。
-
這里用的是 gradle-4.4-all.zip,如果你用的是其它版本,那么可能會下載超級慢,建議改成你電腦中存在的gradle版本,改文件PermissionHelper/gradle/wrapper/gradle-wrapper.properties即可。
-
其它問題可以直接聯系我。
Android 6.0 超級簡單的權限申請2 (Permission)
注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權