Android 8.1 允许安装未知来源权限/允许来自此来源的应用 |
您所在的位置:网站首页 › 怎么样修改安装未知应用 › Android 8.1 允许安装未知来源权限/允许来自此来源的应用 |
之前 6.0 的未知来源权限是一个总的权限,现在单独分开了具体到 app 对应的权限了。具体可见截图 安装未知来源权限其实就是这货 Manifest.permission.REQUEST_INSTALL_PACKAGES,具体的修改代码方案已经在上篇 Android9.0/8.1/6.0 默认给系统 app 授予所有权限中提供了。这篇只是分析解题思路。 核心方法如下 if (checkInstallPackagesPermission(pkgName, mPackageInfo)) { Log.e(TAG, pkgName + " need grant INSTALL_PACKAGES permission"); mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, mPackageInfo.applicationInfo.uid, pkgName, AppOpsManager.MODE_ALLOWED); Log.e(TAG, "grant INSTALL_PACKAGES permission done"); } private static boolean checkInstallPackagesPermission(String packageName, PackageInfo mPackageInfo){ int uid = mPackageInfo.applicationInfo.uid; //boolean permissionGranted = hasPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES, uid); boolean permissionRequested = hasRequestedAppOpPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES, packageName); int appOpMode = getAppOpMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, uid, packageName); return appOpMode != AppOpsManager.MODE_DEFAULT || permissionRequested; } private static int getAppOpMode(int appOpCode, int uid, String packageName) { return mAppOpsManager.checkOpNoThrow(appOpCode, uid, packageName); } private static boolean hasRequestedAppOpPermission(String permission, String packageName) { try { String[] packages = mIpm.getAppOpPermissionPackages(permission); return ArrayUtils.contains(packages, packageName); } catch (Exception exc) { Log.e(TAG, "PackageManager dead. Cannot get permission info"); return false; } }从 Settings 说起,我们看见的设置界面中有允许未知来源的 Preference,经过搜索找到 InstalledAppDetails,允许未知来源是动态增加的 Preference ,看如下代码 vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\applications\InstalledAppDetails.java private void addDynamicPrefs() { if (UserManager.get(getContext()).isManagedProfile()) { return; } ... boolean isPotentialAppSource = isPotentialAppSource(); if (isPotentialAppSource) { Preference pref = new Preference(getPrefContext()); pref.setTitle(R.string.install_other_apps); pref.setKey("install_other_apps"); pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { startAppInfoFragment(ExternalSourcesDetails.class, getString(R.string.install_other_apps)); return true; } }); category.addPreference(pref); } } addAppInstallerInfoPref(screen); maybeAddInstantAppButtons(); } private boolean isPotentialAppSource() { AppStateInstallAppsBridge.InstallAppsState appState = new AppStateInstallAppsBridge(getContext(), null, null) .createInstallAppsStateFor(mPackageName, mPackageInfo.applicationInfo.uid); return appState.isPotentialAppSource(); }isPotentialAppSource 值决定当前 app 详情页面是否需要显示允许来自此来源的应用,isPotentialAppSource() 中初始化了 AppStateInstallAppsBridge对象,并由该对象的isPotentialAppSource()返回。 vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\applications\AppStateInstallAppsBridge.java InstallAppsState createInstallAppsStateFor(String packageName, int uid) { final InstallAppsState appState = new InstallAppsState(); appState.permissionRequested = hasRequestedAppOpPermission( Manifest.permission.REQUEST_INSTALL_PACKAGES, packageName); appState.permissionGranted = hasPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES, uid); appState.appOpMode = getAppOpMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, uid, packageName); return appState; } public static class InstallAppsState { boolean permissionRequested; boolean permissionGranted; int appOpMode; public InstallAppsState() { this.appOpMode = AppOpsManager.MODE_DEFAULT; } .... public boolean isPotentialAppSource() { Log.e("ExternalSources","appOpMode="+(appOpMode != AppOpsManager.MODE_DEFAULT)); Log.e("ExternalSources","permissionRequested="+permissionRequested); return appOpMode != AppOpsManager.MODE_DEFAULT || permissionRequested; } .... }InstallAppsState 构造函数初始化将赋值 appOpMode = AppOpsManager.MODE_DEFAULT, appOpMode 的取值有 public static final int MODE_ALLOWED = 0; public static final int MODE_IGNORED = 1; public static final int MODE_ERRORED = 2; public static final int MODE_DEFAULT = 3; isPotentialAppSource() 的返回值取决于 appOpMode 和 permissionRequested,这两值在 createInstallAppsStateFor() 被重新赋值,继续看对应的方法 public AppStateInstallAppsBridge(Context context, ApplicationsState appState, Callback callback) { super(appState, callback); mIpm = AppGlobals.getPackageManager(); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } private boolean hasRequestedAppOpPermission(String permission, String packageName) { try { Log.e(TAG, "packageName "+packageName); String[] packages = mIpm.getAppOpPermissionPackages(permission); for (String pck : packages) { Log.e(TAG, "PackageManager "+pck); } return ArrayUtils.contains(packages, packageName); } catch (RemoteException exc) { Log.e(TAG, "PackageManager dead. Cannot get permission info"); return false; } } private int getAppOpMode(int appOpCode, int uid, String packageName) { return mAppOpsManager.checkOpNoThrow(appOpCode, uid, packageName); }通过 AppOpsManager 获取当前 app 的模式 通过 IPackageManager 获取包含 REQUEST_INSTALL_PACKAGES 权限的包名数组,判断当前包名是否在其中 好了,是否需要显示此权限的逻辑搞清楚了,接下来再看如何授权? InstalledAppDetails 中 Preference 点击事件对应 startAppInfoFragment(ExternalSourcesDetails.class, getString(R.string.install_other_apps)); 对应的页面为 ExternalSourcesDetails vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\applications\ExternalSourcesDetails.java @Override public boolean onPreferenceChange(Preference preference, Object newValue) { final boolean checked = (Boolean) newValue; if (preference == mSwitchPref) { if (mInstallAppsState != null && checked != mInstallAppsState.canInstallApps()) { if (Settings.ManageAppExternalSourcesActivity.class.getName().equals( getIntent().getComponent().getClassName())) { setResult(checked ? RESULT_OK : RESULT_CANCELED); } setCanInstallApps(checked); refreshUi(); } return true; } return false; } private void setCanInstallApps(boolean newState) { mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, mPackageInfo.applicationInfo.uid, mPackageName, newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED); }点击 RestrictedSwitchPreference 时通过 AppOpsManager 修改 mode 为 AppOpsManager.MODE_ALLOWED |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |