android 6.0以后明场,新增加了動態(tài)申請權(quán)限這一要求交掏,具體是怎么回事呢?
1.概述
- 關(guān)于運(yùn)行時權(quán)限
在Android6.0開始拖叙,App可以直接安裝诅炉,App在運(yùn)行時一個一個詢問用戶授予權(quán)限蜡歹,系統(tǒng)會彈出一個對話框讓用戶選擇是否授權(quán)某個權(quán)限給App(這個Dialog不能由開發(fā)者定制),當(dāng)App需要用戶授予不恰當(dāng)?shù)臋?quán)限的時候涕烧,用戶可以拒絕月而,用戶也可以在設(shè)置頁面對每個App的權(quán)限進(jìn)行管理。
特別注意:這個對話框不是開發(fā)者調(diào)用某個權(quán)限的功能時由系統(tǒng)自動彈出议纯,而是需要開發(fā)者手動調(diào)用父款,如果你直接調(diào)用而沒有去申請權(quán)限的話,將會導(dǎo)致App崩潰瞻凤。 - 哪些權(quán)限需要動態(tài)申請
正常權(quán)限: 使用時直接在清單文件中聲明即可憨攒。
危險權(quán)限: 使用時需要動態(tài)申請權(quán)限。
2.申請權(quán)限工具類
申請權(quán)限的流程:
1.判斷是否是 Android 6.0以上
2.判斷權(quán)限(危險權(quán)限)是否申請了
3.沒有申請阀参,去申請
1.定義權(quán)限申請回掉接口
public interface PermissionListener {
// 申請成功
public void onSucceed();
// 申請失敗
public void onFiled();
}
2.申請權(quán)限的工具類
public class PermissionUtils {
//判斷版本是否是6.0
public static boolean isVersionCodeM() {
return Build.VERSION.SDK_INT > Build.VERSION_CODES.M;
}
/**
*
* @param context
* @param permissions
* @return 獲取未授權(quán)的集合
*/
public static List<String> getDeniedList(Context context,String... permissions){
//創(chuàng)建一個未授權(quán)的集合
List<String> deniedList =new ArrayList<>();
//如果傳入為null,返回空的集合
if (permissions.length==0) {
return deniedList;
}
for (String permission : permissions) {
int permissionCode = ContextCompat.checkSelfPermission(context, permission);
if (permissionCode== PackageManager.PERMISSION_DENIED) {
//將沒有授權(quán)的添加到集合
deniedList.add(permission);
}
}
return deniedList;
}
}
3.申請權(quán)限的幫助類 (無界面的fragment)
public class PermissionFragment extends Fragment {
private static final int REQUESTCODE = 66;
private static final int REQUEST_PERMISSION_SETTING = 55;
private PermissionListener mPermissionListener;
private Activity mActivity;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Fragment具有屬性retainInstance肝集,默認(rèn)值為false。當(dāng)設(shè)備旋轉(zhuǎn)時蛛壳,fragment會隨托管activity一起銷毀并重建杏瞻。調(diào)用setRetainInstance(true)方法可保留fragment,
setRetainInstance(true);
}
public void setPermissionListener(PermissionListener permissionListener) {
this.mPermissionListener = permissionListener;
}
@RequiresApi(api = Build.VERSION_CODES.M)
public void requestPermissions(Activity activity, String[] permission) {
this.mActivity = activity;
requestPermissions(permission, REQUESTCODE);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUESTCODE) {
// 獲取未申請的權(quán)限列表
List<String> deniedPermissions = PermissionUtils.getDeniedList(mActivity, permissions);
if (deniedPermissions.size() > 0) {
// 執(zhí)行失敗的方法
onFailed(permissions);
} else {
// 執(zhí)行成功的方法
onSucceed();
}
}
}
/**
* 成功時回調(diào)方法
*/
private void onSucceed() {
if (mPermissionListener != null) {
mPermissionListener.onSucceed();
}
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void onFailed(String[] permissions) {
for (int i = 0; i < permissions.length; i++) {
// 用戶拒絕是true 用戶選擇不再提示是:false
if (!shouldShowRequestPermissionRationale(permissions[i])) {
new AlertDialog.Builder(mActivity)
.setTitle("權(quán)限被拒絕")
.setMessage("權(quán)限管理-->打開拒絕的權(quán)限")
.setPositiveButton("去打開", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
openSetting();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
mPermissionListener.onFiled();
}
})
.show();
return;
}
}
mPermissionListener.onFiled();
}
/**
* 打開應(yīng)用設(shè)置頁面
*/
private void openSetting() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", mActivity.getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
}
@Override
public void onDestroy() {
// 銷毀對象衙荐,防止內(nèi)存泄漏
mActivity = null;
mPermissionListener = null;
super.onDestroy();
}
}
4.申請權(quán)限的幫助類
/**
* Created by LiMing on 2018/4/25.
* QQ:1002464056
* Email: 1002464056@qq.com
* Version:1.0
*/
public class XPermission {
private Activity mActivity;
private PermissionFragment mPermissionFragment;
private static final String TAG = "XPermission";
private String[] mPermissions;
public XPermission(Activity activity) {
this.mActivity = activity;
mPermissionFragment = getPermissionFragment(activity);
}
private PermissionFragment getPermissionFragment(Activity activity) {
//獲取權(quán)限的fragment
PermissionFragment permissionFragment = findPermissionFragment(activity);
boolean isNewInstance = (permissionFragment == null);
if (isNewInstance) {
permissionFragment = new PermissionFragment();
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager.beginTransaction()
.add(permissionFragment, TAG)
.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
return permissionFragment;
}
/**
* 獲取權(quán)限fragment
*
* @param activity
* @return
*/
private PermissionFragment findPermissionFragment(Activity activity) {
return (PermissionFragment) activity.getFragmentManager().findFragmentByTag(TAG);
}
/**
* 要申請的權(quán)限組
*
* @param permissions
* @return
*/
public XPermission permissions(String... permissions) {
mPermissions = permissions;
return this;
}
/**
* 申請權(quán)限
*
* @param permissionListener
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public void request(PermissionListener permissionListener) {
mPermissionFragment.setPermissionListener(permissionListener);
// 1.判斷版本
if (!PermissionUtils.isVersionCodeM()) {
// 版本6.0一下捞挥,直接回調(diào)成功方法
permissionListener.onSucceed();
return;
}
// 版本6.0及以上
// 2.獲取未授權(quán)的列表
List<String> deniedList = PermissionUtils.getDeniedList(mActivity, mPermissions);
if (deniedList.size() > 0) {
// 3.去申請權(quán)限
mPermissionFragment.requestPermissions(mActivity, deniedList.toArray(new String[deniedList.size()]));
} else {
permissionListener.onSucceed();
}
}
}
5.在MainActivity中調(diào)用
public class MainActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//點(diǎn)擊事件
@RequiresApi(api = Build.VERSION_CODES.M)
public void click(View view) {
new XPermission(this)
.permissions(Manifest.permission.CAMERA)
.request(new PermissionListener() {
@Override
public void onSucceed() {
// TODO
Toast.makeText(MainActivity.this,"授權(quán)成功",Toast.LENGTH_SHORT).show();
}
@Override
public void onFiled() {
Toast.makeText(MainActivity.this,"授權(quán)失敗",Toast.LENGTH_SHORT).show();
}
});
}
}
簡單的封裝基本可以滿足使用,代碼易懂忧吟,有特殊需求完全可以去二次封裝砌函,附上鏈接地址https://github.com/CatEatFishs/XPermission/tree/v1.0
感謝@劉付文 的博客