Android 6.0 引入了运行时权限。就是权限是在程序运行的时候赋予的,而不是安装的时候赋予的。6.0以前权限的赋予都是在安装的时候列出一堆权限,而后用户点击肯定后赋予的。下面对比图,有种你敢看。android
Android L.pngshell
Android M.png数据库
今天来讲下6.0权限赋予的一个过程吧,先不上代码,先用天然语言说一下。
1.并非全部权限都要运行时才申请的。有些是安装的时候天然就给你的,安装时候自动给你的都是一些小权限啦,没啥危险的。执行 adb shell pm dump com.example.rubbishdemo |find "permission" 能够看到有哪些权限是这个com.example.rubbishdemo安装的时候就被赋予的。这个能够叫作“安装时权限”,哈哈,名字是我乱起的。数据结构
Paste_Image.pngide
2.运行时权限的赋予是给整个权限组赋予权限,啥意思啊,是这样的,Android里面的权限都是分组的,便于管理,例如写sd卡,和读sd卡就是同一个权限组android.permission-group.STORAGE的。这些在frameworks/base/core/res/AndroidManifest.xml中定义this
权限组定义.pngspa
权限组下的两个权限.pngcode
3.权限赋予后,会记录到设置数据库中。于是重启也不会失效。xml
下面就进入代码时间
首先是应用部分,在onCreate里面申请发送信息的权限SEND_SMS。ci
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); this.requestPermissions( new String[]{Manifest.permission.SEND_SMS}, 2); }
AndroidManifest定义要获取的权限
<uses-permission android:name="android.permission.SEND_SMS" />
上节咱们说到运行时权限那个弹框是有应用安装器弹出的,所在的Activity是GrantPermissionsActivity。因此,过一下这个Activity的代码。
public void onCreate(Bundle icicle) { super.onCreate(icicle); //mRequestedPermissions是要获取的权限,这里要获取的是android.permission.SEND_SMS mRequestedPermissions = getIntent().getStringArrayExtra( PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES); if (mRequestedPermissions == null) { mRequestedPermissions = new String[0]; } final int requestedPermCount = mRequestedPermissions.length; mGrantResults = new int[requestedPermCount]; //用来保存权限获取结果 //要获取权限的应用的包名 PackageInfo callingPackageInfo = getCallingPackageInfo(); //设备管理器 DevicePolicyManager devicePolicyManager = getSystemService(DevicePolicyManager.class); //权限策略 final int permissionPolicy = devicePolicyManager.getPermissionPolicy(null); //获取应用中全部的权限,这个返回值是AndroidManifest里面定义的全部权限,本例子就是下面一个,only one /* <uses-permission android:name="android.permission.SEND_SMS" /> */ //把这些权限保存到一个数据结构AppPermissions中去 mAppPermissions = new AppPermissions(this, callingPackageInfo, null, false, new Runnable() { @Override public void run() { setResultAndFinish(); } }); for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { //遍历应用的权限组groud boolean groupHasRequestedPermission = false; for (String requestedPermission : mRequestedPermissions) { if (group.hasPermission(requestedPermission)) { //权限组已经有权限了,就不用再次赋予权限了 groupHasRequestedPermission = true; break; } } if (!groupHasRequestedPermission) { continue; } // We allow the user to choose only non-fixed permissions. A permission // is fixed either by device policy or the user denying with prejudice. //根据权限策略赋予权限,正常这两个策略不知足 if (!group.isUserFixed() && !group.isPolicyFixed()) { switch (permissionPolicy) { case DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT: { if (!group.areRuntimePermissionsGranted()) { group.grantRuntimePermissions(false); } group.setPolicyFixed(); } break; case DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY: { if (group.areRuntimePermissionsGranted()) { group.revokeRuntimePermissions(false); } group.setPolicyFixed(); } break; default: { if (!group.areRuntimePermissionsGranted()) { //把要申请权限的权限组groud放在数据结构mRequestGrantPermissionGroups mRequestGrantPermissionGroups.put(group.getName(), new GroupState(group)); } else { group.grantRuntimePermissions(false); updateGrantResults(group); } } break; } } else { // if the permission is fixed, ensure that we return the right request result updateGrantResults(group); } } //弹出弹框 mViewHandler = new GrantPermissionsDefaultViewHandler(this).setResultListener(this); setContentView(mViewHandler.createView()); }
先看一下上面的注释,大概步骤是
1.获取APK AndroidManifest中定义的全部权限,并保存在结构AppPermissions。
本例子只定义了一个权限android.permission.SEND_SMS,因此AppPermissions结构中只包含一个Permission,若是定义了多个Permission,则AppPermissions结构中包含多个Permission。
2.获取APK的权限组AppPermissionGroup ,本例子只定义了一个权限,因此权限组也只有一个。android.permission.SEND_SMS所在的权限组是android.permission-group.SMS。
3.查看要获取的权限所在的权限组是否以前已经获取到权限,若是已经获取到,再也不获取。直接结束,不然会弹个框,吓吓你。
4.弹框经过GrantPermissionsDefaultViewHandler建立。
弹框吓吓你.png
下面进入GrantPermissionsDefaultViewHandler看看
//建立了弹框,只关注赞成按钮 public View createView() { mAllowButton = (Button) mRootView.findViewById(R.id.permission_allow_button); mDenyButton = (Button) mRootView.findViewById(R.id.permission_deny_button); return mRootView; } //看点击容许是怎么处理 public void onClick(View view) { switch (view.getId()) { case R.id.permission_allow_button: if (mResultListener != null) { view.clearAccessibilityFocus(); mResultListener.onPermissionGrantResult(mGroupName, true, false); //这里的mResultListener就是GrantPermissionsActivity } break; } } //GrantPermissionsActivity中 public void onPermissionGrantResult(String name, boolean granted, boolean doNotAskAgain) { GroupState groupState = mRequestGrantPermissionGroups.get(name); if (groupState.mGroup != null) { if (granted) { groupState.mGroup.grantRuntimePermissions(doNotAskAgain); //这里会往设置数据库写一个值,完成权限赋予 groupState.mState = GroupState.STATE_ALLOWED; } }
能够看到,步骤也很简单
1.弹框建立了容许与拒绝的按钮,给按钮设置监听。
2.按下容许按键后,会给权限组赋予权限,最后调用PackageManagerService系统服务将结果写入设置数据库。groupState.mGroup就是权限组。
1.6.0的权限赋予是给整个权限组赋予权限。
2.权限赋予的入口是应用安装器。
3.有些权限是安装时赋予的,是没啥危险的权限。危险的权限经过运行时赋予。至于危险的定义也在frameworks/base/core/res/AndroidManifest.xml中,截个图你看
危险.png
不危险.png
做者:九九叔 连接:https://www.jianshu.com/p/d31ea81f75a3 來源:简书 著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。