一、概述
Android 6.0 (API 23) 之前应用的权限在安装时全部授予,运行时应用不再需要询问用户。在 Android 6.0 或更高版本对权限进行了分类,对某些涉及到用户隐私的权限可在运行时根据用户的需要动态授予。
Android 6.0以下,在AndroidManifest.xml文件中注册权限即可。 Android 6.0及其以后,既要在AndroidManifest.xml文件中注册,又要动态申请危险权限。
二、Android系统权限
两个最重要保护级别是 正常权限 和 危险权限:
(1)正常权限:涵盖应用需要访问其沙盒外部数据或资源,但对用户隐私或其他应用操作风险很小的区域。这些权限在应用安装时授予,运行时不再询问用户。例如: 网络访问、WIFI状态、音量设置等。完整的正常权限列表参考官网?正常权限。
(2)危险权限:涵盖应用需要涉及用户隐私信息的数据或资源,或者可能对用户存储的数据或其他应用的操作产生影响的区域。例如: 读取通讯录、读写存储器数据、获取用户位置等。如果应用声明需要这些危险权限,则必须在运行时明确告诉用户,让用户手动授予。
权限组名 | 权限名称 |
---|
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 | ERAD_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 |
PS: 在 AndroidManifest.xml 声明过的危险权限对应的权限组可以在系统 “设置” -> “应用” -> “应用信息” -> “权限” 中查看,可以手动授权和取消授权。
权限组和权限在Android代码中以 字符串常量 来表示,分别定义在以下两个 静态内部类 的字段中:
- android.Manifest.permission_group(权限组):
- Manifest.permission_group.CALENDAR
- Manifest.permission_group.STORAGE
- ......
- android.Manifest.permission(权限):
- Manifest.permission.READ_CALENDAR
- Manifest.permission.READ_EXTERNAL_STORAGE
- ......
三、动态申请权限
首先,需要在AndroidManifest.xml清单中静态申请权限,否则无法动态申请权限
AndroidManifest.xml
<manifest ...>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<application ...>
...
</application>
</manifest>
然后,在java代码中写动态申请权限的逻辑代码
MainActivity.java
import android.Manifest;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
/**
* 读取日历
* 相机
* 读取手机联系人
*/
private String[] permissions = new String[]{
Manifest.permission.READ_CALENDAR,
Manifest.permission.CAMERA,
Manifest.permission.READ_CONTACTS
};
private final int MY_REQUEST_CODE = 1000;
private String TAG = "zhumeng";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PackageManager packageManager = this.getPackageManager();
PermissionInfo permissionInfo = null;
// PermissionGroupInfo permissionGroupInfo = null;
for (int i = 0; i < permissions.length; i++) {
try {
permissionInfo = packageManager.getPermissionInfo(permissions[i], 0);
// permissionGroupInfo = packageManager.getPermissionGroupInfo(permissions[i], 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
CharSequence permissionName = permissionInfo.loadLabel(packageManager);
// CharSequence permissionnGropName = permissionGroupInfo.loadLabel(packageManager);
if (ContextCompat.checkSelfPermission(this, permissions[i]) != PackageManager.PERMISSION_GRANTED){
// 未获取权限
Log.i(TAG, "您未获得【" + permissionName + "】的权限 ===>");
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])){
// 这是一个坑,某些手机弹出提示时没有永不询问的复选框,点击拒绝就默认勾上了这个复选框,而某些手机上即使勾选上了永不询问的复选框也不起作用
Log.i(TAG, "您勾选了不再提示【" + permissionName + "】权限的申请");
} else {
ActivityCompat.requestPermissions(this, permissions, MY_REQUEST_CODE);
}
} else {
Log.i(TAG, "您已获得了【" + permissionName + "】的权限");
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PackageManager packageManager = this.getPackageManager();
PermissionInfo permissionInfo = null;
for (int i = 0; i < permissions.length; i++) {
try {
permissionInfo = packageManager.getPermissionInfo(permissions[i], 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
CharSequence permissionName = permissionInfo.loadLabel(packageManager);
if (grantResults[i] == PackageManager.PERMISSION_GRANTED){
Log.i(TAG, "您同意了【" + permissionName + "】权限");
} else {
Log.i(TAG, "您拒绝了【" + permissionName + "】权限");
}
}
}
}
|