一、 Android权限机制介绍
- 权限机制:用于保护用户设备的安全性
二、运行时权限介绍
- 1、运行时权限:在Android 6.0(即targetSdkVersion < 23)前应用直接授予了所有所申请的权限;而在此之后,用户不需要在安装软件时一次性授权所有申请的权限,而是可以在软件的使用过程中再对某一项权限申请进行授权,这就是运行时权限
- 2、运行时权限的核心:在程序运行过程中由用户授权我们去执行某些危险操作,程序是不可以擅自做主去执行这些危险操作的
- 3、Android将所有权限归为两类:①普通权限——系统自动帮我们授权,我们只需在注册文件中声明就行;②危险权限——必须用户手动点击授权才行
- 4、危险权限种类:9组24个权限
三、在程序运行时申请权限
以申请打电话的运行时权限为例:
首先要声明权限:
<uses-permission android:name="android.permission.CALL_PHONE"/>
然后:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
....
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE
!= PackageManager.PERMISSION_GRANTED)){
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CALL_PHONE},1);
}else {
call();
}
}
});
}
private void call(){
....
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
....
}
}
1、首先借助ContextCompat.checkSelfPermission()方法判断用户是不是已经给过我们授权,该方法传入的第二个参数就是具体的权限名
2、若没有授权,则调用ActivityCompat.requestPermissions()方法向用户申请授权,这里传入三个参数,第一个是Activity的实例,第二个是一个String数组,我们把要申请的权限名放在数组中即可,第三个参数是请求码(唯一值)
3、若授权,则调用call()方法直接拨打电话
private void call() {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
call();
}else {
Toast.makeText(this,"你取消了申请",Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
1、在调用了requestPermissions()方法后,系统会弹出一个权限申请的对话框选择同意还是拒绝
2、不论我们是选择同意或拒绝权限申请,最终都会回调到onRequestPermissionsResult()方法中
3、授权结果会封装到grantResults当中,可以通过grantResults存储的结果进行判断是否成功授权
四、关于不再询问选项
不再询问作用:在运行时权限申请时,若第一次拒绝,第二次申请时会出现“不在询问”的选项,若此次依旧拒绝,那么该app此后都将默认为权限被拒绝申请。
我们可以在用户第二次申请拒绝后弹出一个窗口告诫用户该权限的重要性,使得用户再做一次选择,具体实施如下:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
call();
}else {
if(!ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CALL_PHONE)){
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("不开启将无法正常工作")
.setNegativeButton("取消",null)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//处理逻辑
}
}).create();
}
}
break;
default:
}
}
五、关于运行时权限的PermissionsDispatcher框架的使用
框架作用:用户每申请一个运行时权限时,无需再重复的写代码,以节约时间提高效率
1、首先要进行依赖添加
在工程项目的build.gradle下添加:
dependencies {
...
classpath "com.neenbedankt.gradle.plugins:android-apt:1.8"
}
在app的build.gradle下添加:
dependencies {
implementation 'com.github.hotchemi:permissionsdispatcher:2.1.3'
annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:2.1.3'
....
}
2、一些基本注释
- RuntimePermissions:用于注册Activity或Fragment,使他们可以处理权限
- NeedsPermission:在需要获取权限的地方注释用于获取权限
- OnShowRationale:提示用户为何要开启此权限。在用户选择拒绝后,再次需要访问权限时调用
- OnPermissionDenied:用户选择拒绝时提示
- OnNeverAskAgain:用户选择不再询问时提示
3、框架编写
@RuntimePermissions
public class PartyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_party);
Button call = findViewById(R.id.call);
call.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
@NeedsPermission(Manifest.permission.CALL_PHONE)——同意申请时调用
void call(){
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
@OnShowRationale(Manifest.permission.CALL_PHONE)——在用户第一次拒绝后再申请时会自动调用
void showWhy(final PermissionRequest request){
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("提示用户为何要开启此权限")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
request.proceed();//再次执行权限申请
}
}).create();
dialog.show();
}
@OnPermissionDenied(Manifest.permission.CALL_PHONE)——用户第一次拒绝时调用
void showDenied(){
Toast.makeText(this,"用户选择拒绝时的提示",Toast.LENGTH_SHORT).show();
//show();模拟一个show()方法
}
@OnNeverAskAgain(Manifest.permission.CALL_PHONE)——用户第二次拒绝时调用
void showNotAsk(){
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("不开启将无法正常工作")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//执行逻辑
}
}).create();
dialog.show();
}
}
4、在编写完上述框架后先编译程序,在完成编译程序后会自动生成一个PartyActivityPermissionsDispatcher辅助类,剩下的事情交给这个类即可。完整代码如下:
@RuntimePermissions
public class PartyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_party);
Button call = findViewById(R.id.call);
call.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
PartyActivityPermissionsDispatcher.callWithCheck(PartyActivity.this);
}
});
}
@NeedsPermission(Manifest.permission.CALL_PHONE)
void call(){
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
@OnShowRationale(Manifest.permission.CALL_PHONE)
void showWhy(final PermissionRequest request){
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("提示用户为何要开启此权限")
.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
request.proceed();//再次执行权限申请
}
}).create();
dialog.show();
}
@OnPermissionDenied(Manifest.permission.CALL_PHONE)
void showDenied(){
Toast.makeText(this,"用户选择时的提示",Toast.LENGTH_SHORT).show();
//show();模拟一个show()方法
}
@OnNeverAskAgain(Manifest.permission.CALL_PHONE)
void showNotAsk(){
AlertDialog dialog = new AlertDialog.Builder(this)
.setMessage("不开启将无法正常工作")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//执行逻辑
}
}).create();
dialog.show();
}
}
5、执行流程:
- 1)首次点击按钮,弹出权限申请提示框,选择拒绝后会调用showDenied()方法;
- 2)再次点击按钮申请,会调用showWhy()方法,接着通过 request.proceed()方法弹出申请提示框;
- 3)选择不再询问且拒绝后调用showNotAsk()方法