运行时权限
Android 的权限机制从系统的第一个版本开始就已经存在了,只不过之前的权限机制在保护用户安全隐私等方面起到的作用比较有限。为此,Android 6.0 系统中引入了运行时权限这个功能。
在加入了权限声明后,用户主要在两个方面得到了保护。
- 如果用户在低于 6.0 系统的设备上安装该程序,会在安装界面给出提示,知晓该程序一共申请了哪些权限,从而决定是否要安装这个程序。
- 用户可随时在应用程序管理界面查看任意一个程序的权限申请情况,保证程序不会出现各种滥用权限的情况。
在 Android 6.0 系统中加入了运行时权限功能,这样,用户不需要在安装软件时一次性授权所有申请的权限,而是可以在软件的使用过程中再对某一项权限申请进行授权。
Android 将常用权限大致归为两类:普通权限、危险权限。(其实还有一些特殊权限,但使用较少)
- 普通权限:指那些不会直接威胁到用户的安全和隐私的权限,对于这部分权限,系统会自动帮我们进行授权,不需要用户手动操作。
- 危险权限:指那些可能会触及用户隐私或者对设备安全性造成影响的权限,如获取设备联系人信息,定位设备地理位置等,对于这部分权限申请,必须由用户手动授权才行,否则程序就无法使用相应的功能。
到 Android 10 系统为止所有的危险权限
权限组名(group) |
权限名(permission) |
CALENDAR |
READ_CALENDAR WRITE_CALENDAR |
CALL_LOG |
READ_CALL_LOG WRITE_CALL_LOG PROCESS_OUTGOING_CALLS |
CAMERA |
CAMERA |
CONTACTS |
WRITE_CONTACTS READ_CONTACTS(读取系统联系人) GET_ACCOUNTS |
LOCATION |
ACCESS_FINE_LOCATION ACCESS_COARSE_LOCATION ACCESS_BACKGROUND_LOCATION |
MICROPHONE |
RECORD_AUDIO |
PHONE |
READ_PHONE_STATE READ_PHONE_NUMBERS CALL_PHONE ANSWER_PHONE_CALLS ADD_VOICEMAIL USE_SIP ACCEPT_HANDOVER |
SENSORS |
BODY_SENSORS |
ACTIVITY_RECOGNITION |
ACTIVITY_RECOGNITION |
SMS |
SEND_SMS READ_SMS RECEIVE_SMS RECEIVE_MMS RECEIVE_WAP_PUSH |
STORAGE |
READ_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE ACCESS_MEDIA_LOCATION |
说明:
1 2
| 所需权限无论是否是危险权限 均需要在清单文件声明 在旧的权限管理系统中,权限仅仅在App安装时询问用户一次,用户同意了这些权限,App才能被安装,App一旦安装后后授权不可取消。Android 6.0 的已授权运行时权限可在手机设置内取消权限。
|
查看权限目录:
1 2
| 通过 adb shell 命令 查看危险权限 adb shell pm list permissions -d -g
|
注意:原则上,用户一旦同意了某个权限申请后,同组的其它权限也会被系统自动授权。但是,不要基于此规则来实现任何功能逻辑,因为 Android 系统随时有可能调整权限的分组。
示例
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
| public class MainActivity extends BaseActivity{
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
requestPermiss(); }
private void requestPermiss() { request(new OnPermissionsResult() { @Override public void OnSuccess() {
}
@Override public void OnFail(List<String> noPermissions) { LogUtils.d("noPermissions:" + noPermissions.toString()); } }); } }
|
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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
| public class BaseActivity extends AppCompatActivity {
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); }
private static final int PERMISSION_REQUEST_CODE = 1000; public static final int PERMISSION_WINDOW_REQUEST_CODE = 1001;
private String[] mStrPermission = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.RECORD_AUDIO, Manifest.permission.CALL_PHONE, Manifest.permission.ACCESS_FINE_LOCATION
};
private List<String> mPerList = new ArrayList<>(); private List<String> mPerNoList = new ArrayList<>();
private OnPermissionsResult permissionsResult;
protected void request(OnPermissionsResult permissionsResult) { if (!checkPermissionsAll()) { requestPermissionAll(permissionsResult); } }
protected boolean checkPermissions(String permissions) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int check = checkSelfPermission(permissions); return check == PackageManager.PERMISSION_GRANTED; } return false; }
protected boolean checkPermissionsAll() { mPerList.clear(); for (int i = 0; i < mStrPermission.length; i++) { boolean check = checkPermissions(mStrPermission[i]); if (!check) { mPerList.add(mStrPermission[i]); } } return mPerList.size() > 0 ? false : true; }
protected void requestPermission(String[] mPermissions) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(mPermissions, PERMISSION_REQUEST_CODE); } }
protected void requestPermissionAll(OnPermissionsResult permissionsResult) { this.permissionsResult = permissionsResult; requestPermission((String[]) mPerList.toArray(new String[mPerList.size()])); }
@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { mPerNoList.clear(); if (requestCode == PERMISSION_REQUEST_CODE) { if (grantResults.length > 0) { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_DENIED) { mPerNoList.add(permissions[i]); } } if (permissionsResult != null) { if (mPerNoList.size() == 0) { permissionsResult.OnSuccess(); } else { permissionsResult.OnFail(mPerNoList); } } } } super.onRequestPermissionsResult(requestCode, permissions, grantResults); }
protected interface OnPermissionsResult { void OnSuccess();
void OnFail(List<String> noPermissions); }
protected boolean checkWindowPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return Settings.canDrawOverlays(this); } return true; }
protected void requestWindowPermissions() { Toast.makeText(this, "申请窗口权限,暂时没做UI交互", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION , Uri.parse("package:" + getPackageName())); startActivityForResult(intent, PERMISSION_WINDOW_REQUEST_CODE); } }
|
AndroidManifest.xml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.framework">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <uses-permission android:name="android.permission.CALL_PHONE"/> </manifest>
|
##示例(Kotlin)
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 66 67 68
|
class PermissionActivity :BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_permission)
btnCall.setOnClickListener{ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)!=PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.CALL_PHONE),1) }else { call() } } }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) when(requestCode){ 1 -> { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){ call() }else{ Toast.makeText(this,"You denied the permission",Toast.LENGTH_SHORT).show() } } } }
private fun call(){
try { val intent = Intent(Intent.ACTION_CALL) intent.data = Uri.parse("tel:1008611") startActivity(intent) }catch (e: SecurityException){ e.printStackTrace() } } companion object{ fun actionStart(context: Context){ val intent = Intent(context, PermissionActivity::class.java) context.startActivity(intent) } } }
|
备注
参考资料:
第一行代码(第3版)