序
自从升级到Android M以来,最大的改变就是增加了运行时权限RuntimePermission,6.0以上的系统如果没有做适配,运行了targetSDK=23的App时就会报权限错误。我们知道6.0以下的系统是按照的时候权限申请的,6.0和之后的版本是我们想要使用某个app的权限,去动态申请的,这也是基于安全上的考虑吧(比如:单机的象棋对战,请求访问通讯录权限等不合理的权限,这肯定是有问题的)。
为了保护用户的隐私,谷歌官方将权限分为了两类,一个是正常权限(Normal Permissions),这类权限不涉及用户隐私,是不需要用户进行授权的,比如访问网络,手机震动等。还有一类是危险权限(Dangerous Permissions),一般是涉及到用户隐私的,需要用户进行授权,比如操作SD卡的写入,相机,录音等。
我们来看一张权限的清单文件:
我们可以通过adb shell pm list permissions -d -g进行查看。
权限如何申请
那么对于我们开发者来说,怎么适配6.0呢?按着官方的api走就行:
1,在AndroidManifest文件中添加需要的权限。
2,检查权限
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { }else{ // }
3,申请授权
ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS);
4,处理权限申请回调
@Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_READ_CONTACTS: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // contacts-related task you need to do. } else { // permission denied, boo! Disable the // functionality that depends on this permission. } return; } } }
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. }
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity, Manifest.permission.READ_CONTACTS)) { // Show an expanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(thisActivity, new String[]{Manifest.permission.READ_CONTACTS}, MY_PERMISSIONS_REQUEST_READ_CONTACTS); // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an // app-defined int constant. The callback method gets the // result of the request. } }
权限工具类:
public class PermissionUtils { private static final ArrayMap<String, Integer> MIN_SDK_PERMISSIONS; static { MIN_SDK_PERMISSIONS = new ArrayMap<>(8); MIN_SDK_PERMISSIONS.put("com.android.voicemail.permission.ADD_VOICEMAIL", 14); MIN_SDK_PERMISSIONS.put("android.permission.BODY_SENSORS", 20); MIN_SDK_PERMISSIONS.put("android.permission.READ_CALL_LOG", 16); MIN_SDK_PERMISSIONS.put("android.permission.READ_EXTERNAL_STORAGE", 16); MIN_SDK_PERMISSIONS.put("android.permission.USE_SIP", 9); MIN_SDK_PERMISSIONS.put("android.permission.WRITE_CALL_LOG", 16); MIN_SDK_PERMISSIONS.put("android.permission.SYSTEM_ALERT_WINDOW", 23); MIN_SDK_PERMISSIONS.put("android.permission.WRITE_SETTINGS", 23); } private static volatile int targetSdkVersion = -1; public static boolean checkPermissions(int... grantResults) { if (grantResults.length == 0) { return false; } for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } public static boolean hasSelfPermissions(Context context, String... permissions) { for (String permission : permissions) { if (permissionExists(permission) && !hasSelfPermission(context, permission)) { return false; } } return true; } private static boolean permissionExists(String permission) { Integer minVersion = MIN_SDK_PERMISSIONS.get(permission); return minVersion == null || Build.VERSION.SDK_INT >= minVersion; } private static boolean hasSelfPermission(Context context, String permission) { try { return PermissionChecker.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; } catch (RuntimeException t) { return false; } } public static boolean shouldShowRequestPermissionRationale(Activity activity, String... permissions) { for (String permission : permissions) { if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { return true; } } return false; } @TargetApi(Build.VERSION_CODES.DONUT) public static int getTargetSdkVersion(Context context) { try { if (targetSdkVersion != -1) { return targetSdkVersion; } PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); targetSdkVersion = packageInfo.applicationInfo.targetSdkVersion; } catch (PackageManager.NameNotFoundException ignored) { } return targetSdkVersion; } }
基类:
public class BasePermissionActivity extends AppCompatActivity { private PermissionHandler mHandler=null; private static int requesrCode=001; /** * 请求权限 */ protected void requestPermission(String[] permissions, PermissionHandler handler) { if (PermissionUtils.hasSelfPermissions(this, permissions)) { handler.onGranted(); } else { mHandler = handler; ActivityCompat.requestPermissions(this, permissions, requesrCode); } } protected void requestPermission( PermissionHandler handler,String permissions) { if (PermissionUtils.hasSelfPermissions(this, permissions)) { handler.onGranted(); } else { mHandler = handler; ActivityCompat.requestPermissions(this, new String[]{permissions} , requesrCode); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (mHandler == null) return; if (PermissionUtils.checkPermissions(grantResults)) { mHandler.onGranted(); } else { if (!PermissionUtils.shouldShowRequestPermissionRationale(this, permissions)) { if (!mHandler.onNeverRequest()) { Toast.makeText(this, "权限已被拒绝,请在设置-应用-权限中打开", Toast.LENGTH_SHORT).show(); } } else { mHandler.onDenied(); } } } public abstract class PermissionHandler { //权限通过 public abstract void onGranted(); //权限拒绝 public void onDenied() { } //不再询问 public boolean onNeverRequest() { return false; } } }
public class MainActivity extends BasePermissionActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { request1(); } private void request1() { requestPermission(new String[]{Manifest.permission.CAMERA}, new PermissionHandler() { @Override public void onGranted() { Intent intent = new Intent(); //调用照相机 intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); startActivity(intent); } @Override public void onDenied() { Toast.makeText(MainActivity.this, "拒绝", Toast.LENGTH_SHORT).show(); } }); } private void request2() { requestPermission(new String[]{Manifest.permission.CAMERA}, new PermissionHandler() { @Override public void onGranted() { Intent intent = new Intent(); //调用照相机 intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); startActivity(intent); } @Override public void onDenied() { Toast.makeText(MainActivity.this, "拒绝", Toast.LENGTH_SHORT).show(); } }); } }代码: https://github.com/xiangzhihong/permissionDemo
最后附上鸿洋封装的比较好的库:https://github.com/lovedise/PermissionGen