从Android6.0
开始,Google调整了应用的权限申请方案。调整之后将权限分级,分成了普通权限
和危险权限
,普通权限的授权方式跟之前一样,只需要在Manifest
文件中申明即可,危险权限不仅需要在Manifest
文件中声明,还需要在程序中调用官方提供的Api主动申请。
Android6.0
以后,一共将动态权限分成了9组,每组只要有一个权限申请成功了,就默认整组权限都可以使用了。这九组权限分别如下:
权限组名称 | 权限组 | 权限组权限成员 |
---|---|---|
读写联系人 | group:android.permission-group.CONTACTS | permission:android.permission.WRITE_CONTACTS permission:android.permission.GET_ACCOUNTS permission:android.permission.READ_CONTACTS |
电话 | group:android.permission-group.PHONE | permission:android.permission.READ_CALL_LOG permission:android.permission.READ_PHONE_STATE permission:android.permission.CALL_PHONE permission:android.permission.WRITE_CALL_LOG permission:android.permission.USE_SIP permission:android.permission.PROCESS_OUTGOING_CALLS permission:com.android.voicemail.permission.ADD_VOICEMAIL |
日历信息 | group:android.permission-group.CALENDAR | permission:android.permission.READ_CALENDAR permission:android.permission.WRITE_CALENDAR |
相机 | group:android.permission-group.CAMERA | permission:android.permission.CAMERA |
传感器 | group:android.permission-group.SENSORS | permission:android.permission.BODY_SENSORS |
地理位置 | group:android.permission-group.LOCATION | permission:android.permission.ACCESS_FINE_LOCATION permission:android.permission.ACCESS_COARSE_LOCATION |
存储卡 | group:android.permission-group.STORAGE | permission:android.permission.READ_EXTERNAL_STORAGE permission:android.permission.WRITE_EXTERNAL_STORAGE |
多媒体 | group:android.permission-group.MICROPHONE | permission:android.permission.RECORD_AUDIO |
SMS | group:android.permission-group.SMS | permission:android.permission.READ_SMS permission:android.permission.RECEIVE_WAP_PUSH permission:android.permission.RECEIVE_MMS permission:android.permission.RECEIVE_SMS permission:android.permission.SEND_SMS permission:android.permission.READ_CELL_BROADCASTS |
由于低于API 23
是不需要使用动态权限申请的,我们需要先判断一下系统版本,代码如下是Android 6.0以上
的系统还是Android 6.0以下
的系统。用ContextCompat
类中的checkSelfPermission
方法进行是否有权限判断。
public static int checkSelfPermission(@NonNull Context context, @NonNull String permission) {
if (permission == null) {
throw new IllegalArgumentException("permission is null");
}
return context.checkPermission(permission, android.os.Process.myPid(), Process.myUid());
}
具体使用方法如下:
if (Build.VERSION.SDK_INT >= 23) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
//无该权限,需要申请
}
} else { //低于23 不需要处理
}
在步骤的的checkSelfPermission
方法中如果判断没有权限,就需要用到ActivityCompat
类中的requestPermissions
方法进行动态权限申请,该方法需要传一个需要申请权限名称的权限permissions
数组。
public static void requestPermissions(final @NonNull Activity activity,
final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode) {
}
申请方法如下:先定一个需要申请权限的权限数组PERMISSIONS_STORAGE
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"};
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
由于权限申请是异步的,用户完成了以后,需要回调函数处理,
Activity
中提供了一个回调处理方法onRequestPermissionsResult
,只需要重写该方法即可
case 中的参数REQUEST_EXTERNAL_STORAGE
即步骤2申请权限中定一个的参数
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_EXTERNAL_STORAGE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show();
}
}
}
}
我们以申请SD卡读写权限为例,完整代码如下:
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= 23) {
checkPermission();
}
}
private void checkPermission() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission
.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "请开通相关权限,否则无法正常使用本应用!", Toast.LENGTH_SHORT).show();
}
//申请权限
ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
} else {
Toast.makeText(this, "已授权成功!", Toast.LENGTH_SHORT).show();
dothings();
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_EXTERNAL_STORAGE: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
dothings();
Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show();
}
}
}
}
public void dothings() {
}
}
AndroidManifest.xml声明权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
RxPermission
可以帮助开发者简化获取权限的相关处理操作,而且内部也自动帮我们判断了版本是否需要申请权限。同时结合RxJava
可以方便的回调各种结果。
官网:https://github.com/tbruyelle/RxPermissions
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
}
由于rxpermissions
需要用到rxjava,所有rxjava
的包也一起引入。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA"/>
RxPermissions permissions = new RxPermissions(this);
permissions.request(Manifest.permission.CAMERA)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) {
if (aBoolean ) {
Toast.makeText(MainActivity.this, "授权成功!", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "授权失败!", Toast.LENGTH_SHORT).show();
}
}
});
RxPermissions permissions = new RxPermissions(this);
permissions.request(Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE)
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean aBoolean) {
if (aBoolean ) {
Toast.makeText(MainActivity.this, "授权成功!", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "授权失败!", Toast.LENGTH_SHORT).show();
}
}
});
AndPermission
跟前面的RxPermission
使用方法类似
官网:https://github.com/yanzhenjie/AndPermission
implementation 'com.yanzhenjie:permission:2.0.3'
AndPermission.with(this)
.runtime()
.permission(Permission.WRITE_EXTERNAL_STORAGE,Permission.CAMERA)
.onGranted(permissions -> {
Toast.makeText(MainActivity.this, "授权成功!", Toast.LENGTH_SHORT).show();
})
.onDenied(permissions -> {
Toast.makeText(MainActivity.this, "授权失败!", Toast.LENGTH_SHORT).show();
})
.start();