Android应用权限开关管理,代码方式设置以及过程记录

您所在的位置:网站首页 安卓位置授权怎么取消 Android应用权限开关管理,代码方式设置以及过程记录

Android应用权限开关管理,代码方式设置以及过程记录

2024-07-10 15:36| 来源: 网络整理| 查看: 265

请注意!!!本文介绍如何以系统应用的方式去设置其他应用的权限开关

请注意!!!本文介绍如何以系统应用的方式去设置其他应用的权限开关

请注意!!!本文介绍如何以系统应用的方式去设置其他应用的权限开关,以系统图册Gally为例

授人以鱼不如授人以渔,本文还会写出思路和过程

开始前,请确认能够对应用进行系统签名,Here we go!

思路一,使用DevicePolicyManager去设置应用权限,这个涉及到设备管理器参考我之前的文章,实现起来比较复杂,如果我们只是想要单纯开关一次那么就没必要这么麻烦,我们这里就不这样实现了,看二。

思路二,先找到系统设置里面是怎么做的,那么我们就在设置权限里面找下,我们先来到这个页面

这个页面没什么特别的就是一些开关,我们想要了解按了开关之后做了什么,本次以打开Storage权限为例,所以先手动关闭Storage权限,然后在shell里面运行以下指令

adb shell dumpsys activity top TASK com.android.settings.root id=31 userId=0 ACTIVITY com.android.packageinstaller/.permission.ui.ManagePermissionsActivity 5d608b0 pid=2736 Local Activity f578807 State: mResumed=true mStopped=false mFinished=false mChangingConfigurations=false

看到当前的任务栈顶是ManagePermissionsActivity 这个类,我们去找到这个类看下这里面做了什么

分析了一下这个类就是一个Activity,在它的OnCreate方法里面根据上一个页面传递的Action去case不同的Fragment,根据字段EXTRA_PACKAGE_NAME 可以猜测到这个case下面的操作就是我们想要的获取fragment的地方,看下代码

case Intent.ACTION_MANAGE_APP_PERMISSIONS: { String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); if (packageName == null) { Log.i(LOG_TAG, "Missing mandatory argument EXTRA_PACKAGE_NAME"); finish(); return; } if (DeviceUtils.isAuto(this)) { fragment = com.android.packageinstaller.permission.ui.auto .AppPermissionsFragment.newInstance(packageName); } ...后面还有代码不展示了,主要就是AppPermissionsFragment这个 }

我们看下AppPermissionsFragment这里面做了什么,这个类里面主要就是加载了设置相关权限的Preferences,不同的app申请的权限不一样,会根据具体的应用显示对应的开关没有对应的属性就直接跳过,有这个权限就会显示,这个具体应用权限是在包解析的时候完成的,重要的是这里面设置了Preferences的点击事件,那么我们关心的点击了开关之后做了什么就在这里面了,找到设置按钮改变的监听的位置代码

private void loadPreferences() { for (AppPermissionGroup group : mAppPermissions.getPermissionGroups()) { ... preference.setOnPreferenceChangeListener(this); ... } }

在这里设置了this,那么说这个Fragment实现了状态改变监听器,我们找到这个监听器里面做了什么,看代码,省略了无关代码

@Override public boolean onPreferenceChange(final Preference preference, Object newValue) { ... if (newValue == Boolean.TRUE) { group.grantRuntimePermissions(false); } ... }

看到这个Preference改变成TRUE时调用了 grantRuntimePermissions这个方法,这个group是什么,看引用,这个是一个AppPermissionGroup类,我们找到这个类里面的这个方法,看做了什么

public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) { ... if (!permission.isGranted()) { permission.setGranted(true); mPackageManager.grantRuntimePermission(mPackageInfo.packageName, permission.getName(), mUserHandle); } ... }

这里面调用了,PackageManager的grantRuntimePermission,不过这个方法是一个SystemApi,我们不能直接使用,需要反射调用。

观察一下里面需要传的值,是包名、权限名、UserHandle,这里我们要设置Gally的权限所以包名是com.android.gally3d 要设置的权限名在 Manifest.permission.READ_EXTERNAL_STORAGE,所以我们还差一个UserHandle,我们要先了解UserHandle是什么,可以看这个文章 https://www.jianshu.com/p/0b60331efe07

经过了解是一个记录多用户的 userid  uid这些,里面有一个静态方法getUserHandleForUid(int uid)这个uid可以通过PackageManager获取那么我们就可以构造这个类的实例了

int uid = packageManager.getApplicationInfo("com.android.settings", 0).uid; UserHandle userHandle = UserHandle.getUserHandleForUid(uid);

需要的三个参数都有了,下面我们开始反射,再次提醒,想要设置成功,必须在Manifest里面ju具有这个属性android:sharedUserId="android.uid.system",并且是系统签名才行,开始

解释一下,在获取uid时我们选择com.android.settings是因为我们要以system权限去设置所以uid也应该是系统的,当然我们自己的应用也是系统权限,获取自己的uid也没问题这两个是同一个uid

private void grant(PackageManager packageManager) { try { int uid = packageManager.getApplicationInfo("com.android.settings", 0).uid; UserHandle userHandle = UserHandle.getUserHandleForUid(uid); Class refPackageManager = packageManager.getClass(); Method refGrantRuntimePermission = refPackageManager.getDeclaredMethod("grantRuntimePermission", String.class, String.class, UserHandle.class); refGrantRuntimePermission.setAccessible(true); refGrantRuntimePermission.invoke(packageManager,"com.android.gallery3d",Manifest.permission.READ_EXTERNAL_STORAGE,userHandle); } catch (Exception e) { } }

然后我们运行试下效果,OK可以打开权限了,那么想要关闭权限怎么做,可以对照这个跟踪方式找下关闭权限的方法



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3