(1).由于MIUI等部分国产定制系统也有权限管理,没有相关api,故无法判断用户是否允许获取联系人等隐私。在Android 6.0之后,新增权限管理可以通过官方api判断用户的运行状态;
(2).我们指定targetSdkVersion为23或者之后我们还需要在运行时请求这些所需的权限。这很重要,因为已经出现了很多开发者把targetSdkVersion飙到了最新,然后发现自己的app疯狂的崩溃,这是由于他们没有实现执行运行时权限请求的代码。当你已经把一个targeting API 为23或者之后的app发布到了Google Play上,这更是一个问题,你无法立即把那个apk的targeting API替换成更早的版本。
从Android6.0开始,权限分为普通权限和许可权限。许可权限分类归组,一个权限授权之后,该组下的权限均可使用。
只需要在xml申请即可,使用方法和之前6.0以前的一样。在应用安装应用时,会默认获得许可。
可执行 $adb shell pm list permissions -d -g
| Permission Group | Permissions | 
|---|---|
| android.permission-group.CALENDAR | 
 | 
| android.permission-group.CAMERA | 
 | 
| android.permission-group.CONTACTS | 
 | 
| android.permission-group.LOCATION | 
 | 
| android.permission-group.MICROPHONE | 
 | 
| android.permission-group.PHONE | 
 | 
| android.permission-group.SENSORS | 
 | 
| android.permission-group.SMS | 
 | 
| android.permission-group.STORAGE | 
 | 
同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了。
源码中被用来检查和请求权限的方法分别是Activity的checkSelfPermission和requestPermissions,这些方法api23引入。
检查应用是否拥有该权限,被授权返回值为PERMISSION_GRANTED,否则返回PERMISSION_DENIED
将弹出请求授权对话框,这个方法在M之前版本调用,OnRequestPermissionsResultCallback 直接被调用,带着正确的 PERMISSION_GRANTED或者 PERMISSION_DENIED 。
该方法类似于Activity的OnActivityResult()的回调方法,主要接收请求授权的返回值
| 1 2 3 4 5 6 7 8 9 10 | //版本判断if(Build.VERSION.SDK_INT >= 23) {      //减少是否拥有权限      intcheckCallPhonePermission = ContextCompat.checkSelfPermission(getApplicationContext(), permission);      if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {           //弹出对话框接收权限           ActivityCompat.requestPermissions(BaseActivity.this, newString[]{permission}, id);           return;      }} | 
| 1 2 3 4 5 6 7 8 9 | @OverridepublicvoidonRequestPermissionsResult(intrequestCode, @NonNullString[] permissions, @NonNullint[] grantResults) {     super.onRequestPermissionsResult(requestCode, permissions, grantResults);     if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {          //TODO:已授权     } else{          //TODO:用户拒绝     }} | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | publicclassBaseActivity extendsAppCompatActivity {     privateMap<Integer, Runnable> allowablePermissionRunnables = newHashMap<>();     privateMap<Integer, Runnable> disallowablePermissionRunnables = newHashMap<>();     @Override     protectedvoidonCreate(Bundle savedInstanceState) {           super.onCreate(savedInstanceState);     }     /**       * 请求权限       * @param id 请求授权的id 唯一标识即可       * @param permission 请求的权限       * @param allowableRunnable 同意授权后的操作       * @param disallowableRunnable 禁止权限后的操作       */     protectedvoidrequestPermission(intid, String permission, Runnable allowableRunnable, Runnable disallowableRunnable) {          if(allowableRunnable == null) {                 thrownewIllegalArgumentException("allowableRunnable == null");          }          allowablePermissionRunnables.put(id, allowableRunnable);          if(disallowableRunnable != null) {                disallowablePermissionRunnables.put(id, disallowableRunnable);          }          //版本判断          if(Build.VERSION.SDK_INT >= 23) {               //减少是否拥有权限               intcheckCallPhonePermission = ContextCompat.checkSelfPermission(getApplicationContext(), permission);               if(checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {                      //弹出对话框接收权限                      ActivityCompat.requestPermissions(BaseActivity.this, newString[]{permission}, id);                      return;               } else{                      allowableRunnable.run();               }          } else{               allowableRunnable.run();          }    }    @Override    publicvoidonRequestPermissionsResult(intrequestCode, @NonNullString[] permissions, @NonNullint[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {               Runnable allowRun = allowablePermissionRunnables.get(requestCode);               allowRun.run();        } else{               Runnable disallowRun = disallowablePermissionRunnables.get(requestCode);               disallowRun.run();        }    }}publicclassMainActivity extendsBaseActivity implementsView.OnClickListener{     privateButton btCallPhone;     privateButton btContact;     @Override     protectedvoidonCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          btCallPhone = (Button) findViewById(R.id.call_phone);          btContact = (Button) findViewById(R.id.contact);          btCallPhone.setOnClickListener(this);          btContact.setOnClickListener(this);     }     @Override     publicvoidonClick(View v) {          if(v == btCallPhone){               //拨打电话               requestPermission(1, Manifest.permission.CALL_PHONE, newRunnable() {               @Override               publicvoidrun() {                    callPhone();               }          }, newRunnable() {               @Override               publicvoidrun() {                    callPhoneDenied();               }          });     }elseif(v == btContact){          //读取联系人信息          requestPermission(2, Manifest.permission.WRITE_CONTACTS, newRunnable() {                @Override                publicvoidrun() {                     readContact();                }          }, newRunnable() {                @Override                publicvoidrun() {                     readContactDenied();                }          });      }  }  privatevoidcallPhone() {       Toast.makeText(MainActivity.this, "CALL_PHONE OK", Toast.LENGTH_SHORT).show();  }  privatevoidcallPhoneDenied() {      Toast.makeText(MainActivity.this, "CALL_PHONE Denied", Toast.LENGTH_SHORT).show();  }  privatevoidreadContact() {       ContentResolver cr = getContentResolver();       String str[] = {ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.PHOTO_ID};       Cursor cur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, str, null, null, null);       intcount = cur.getCount();       cur.close();       Toast.makeText(MainActivity.this, String.format("发现%s条", count), Toast.LENGTH_SHORT).show();  }  privatevoidreadContactDenied() {      Toast.makeText(MainActivity.this, "Contact Denied", Toast.LENGTH_SHORT).show();  }} | 
原文:http://www.cnblogs.com/Free-Thinker/p/5801113.html