《第一行代码》阅读笔记(二十四)——Android动态请求权限
首先本章就介绍了什么是危险权限,而不是危险权限的就是普通权限。那有那些危险权限呢,不用记,需要的时候直接来这个表里查。「Android中危险权限列表」同时可以访问http://developer.android.com/reference/android/Manifest.permission.html可以查看Android系统中完整的权限列表。
Demo
首先先创建项目,给布局设置一个按钮,就不说了。书上先做了一个错误示范,让大家看看没有权限的时候,程序会怎么报错,有兴趣的可以看看。这里就直奔主题,大家先来看看,完整的Activity。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnCall = findViewById(R.id.btn_call);
btnCall.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
// call();
}
}
});
}
// private void call() {
// try {
// Intent intent = new Intent(Intent.ACTION_CALL);
// intent.setData(Uri.parse("tel:10086"));
// startActivity(intent);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
@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, "You denied the permission", Toast.LENGTH_LONG).show();
}
break;
default:
}
}
}
如果按照书中的写法,封装的call方法会报错,这应该是新版本对动态获取权限的改变。所以笔者做了一些修改。
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
...
} else {
...
}
首先在点击的时候,通过ContextCompat.checkSelfPermission函数接受两个参数,一个是环境,另个一个就是具体的权限名,比如例子中的Manifest.permission.CALL_PHONE。然后用得到的返回值和PackageManager.PERMISSION_GRANTED进行判断。
checkSelfPermission顾名思义就是检查当前环境的权限,而后面跟的参数就是需要检查的权限。而PackageManager.PERMISSION_GRANTED就是手机已经获得的权限。两者对比,就知道当前的APP是否已经获得了权限。根据不同的结果进行接下来的操作。
例子中,如果已经获得,就进行Call的动作。如果没有,就通过ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1)
来申请,三个参数分别是当前环境、权限名数组和为一个请求码,一般传入1就行。这个1会在后面的onRequestPermissionsResult函数中用到。
requestPermissions方法调用后,系统会自动弹出一个请求,需要用户确认,无论用户是否确认,都会进入onRequestPermissionsResult函数,这是一个系统自动生成的函数,虽然没有调用,但是会将授权的结果封装在grantResults参数当中。
@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, "You denied the permission", Toast.LENGTH_LONG).show();
}
break;
default:
}
}
然后进行判断,如果结果集的长度大于零,就说明有权限被申请。并取出第一位,因为我们只申请了一个权限名,所以第一个就是我们申请的值,然后和手机的权限进行比较。其实结果集是一串0和-1的集合,分别和PackageManager包中的两个参数对应。
public static final int PERMISSION_DENIED = -1;
public static final int PERMISSION_GRANTED = 0;
如果用户同意,就进行操作就行了,如果不同意弹出一个toast提示。
requestCode用来判断进入那个switch分支,用来后续多个权限申请的不同提示或者操作。
注意
Android10读写文件权限请求bug——open failed: EACCES (Permission denied)