Android 6.0起权限管理更严格了,朝着IOS权限靠拢了。看来Android也慢慢朝着封闭的方向发展了。如果 targetSdkVersion <23,就没有动态权限问题,但这不是长久之计,迟早要适配的。

Android将权限分为3种:

  • 普通权限(Normal Permissions)
  • 危险权限(Dangerous Permissions)
  • 特殊权限(Special Permissions)

如果 targetSdkVersion>=23 那么就要对 危险权限和 特殊权限动态申请

危险权限(Dangerous Permissions)

Permission Group Permissions
CALENDAR READ_CALENDAR
WRITE_CALENDAR
CAMERA CAMERA
CONTACTS READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATION ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE RECORD_AUDIO
PHONE READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS BODY_SENSORS
SMS SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP
_PUSH RECEIVE_MMS
STORAGE READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

危险权限基本都涉及到用户的隐私,Android系统将这些危险权限分为9组,

获取分组中某个权限的同时也就获取了同组中的其他权限

危险权限不仅需要在 AndroidManifest.xml中注册,还需要动态的申请权限

EasyPermisson 是Google对动态权限申请的封装,Google出品必属精品;

添加依赖

1
2
3
dependencies {
compile 'pub.devrel:easypermissions:0.2.1'
}

AndroidManifest添加权限

1
2
3
<manifest>
<uses-permission android:name="android.permission.CAMERA" />
</manifest>

添加实现(以相机权限为例子)

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
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks{
private static final String TAG="tag";
private static final int CAMERA_PERM = 0x100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
grantCamera();
}
private void openCamera(){
}
@AfterPermissionGranted(CAMERA_PERM)
private void grantCamera() {
if (EasyPermissions.hasPermissions(MainActivity.this, Manifest.permission.CAMERA)) {
//有此权限
openCamera();
} else {//没有此权限,需要重新申请
EasyPermissions.requestPermissions(this, "请求camera权限", CAMERA_PERM, Manifest.permission.CAMERA);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}
@Override
public void onPermissionsGranted(int requestCode, List<String> perms) {
Log.d(TAG,"success");
}
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
new AppSettingsDialog.Builder(this, "点击确定去设置界面设置权限")
.setTitle("Title")
.setPositiveButton("确定")
.setNegativeButton("取消", null /* click listener */)
.setRequestCode(requestCode)
.build()
.show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_PERM) {//从设置权限界面返回
if (EasyPermissions.hasPermissions(MainActivity.this, Manifest.permission.CAMERA)){
}
}
}
}

@AfterPermissionGranted(CAMERA_PERM)注解是在用户同意授权后EasyPermissions再次回调注解的函数;AppSettingsDialog 是googgle封装的直接跳转到设置权限界面dialog;

特殊权限(Special Permissions)

Special Permissions
SYSTEM_ALERT_WINDOW 设置悬浮窗
WRITE_SETTINGS 修改系统设置

特殊权限比危险权限更危险,特殊权限需要在manifest中申请并且通过发送Intent让用户在设置界面进行勾选.

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
public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks{
private static final int SYSTEM_ALERT_WINDOW_PERM = 0x101;
private static final int WRITE_SETTINGS_PERM = 0x102;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
grantAlertWindow();
grantWriteSettings();
}
private void grantAlertWindow(){
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, SYSTEM_ALERT_WINDOW_PERM);
}
private void grantWriteSettings(){
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, WRITE_SETTINGS_PERM );
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == SYSTEM_ALERT_WINDOW_PERM) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if ( Settings.canDrawOverlays(this)){//get
}
}
}else if (requestCode == WRITE_SETTINGS_PERM) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.System.canWrite(this)) {//get
}
}
}
}
}