android 9.0跳过“未知来源”进行安装应用

需求:点击更新应用进行安装的过程中弹出“未知来源”设置提示,需要跳过该步骤直接安装。

方案1 

分析:

1.首先9.0 app安装是通过packages/apps/PackageInstaller里面的应用进行安装的。

2.其次定位到安装界面是/src/com/android/packageinstaller/PackageInstallerActivity.java

3.查看handleUnknownSources里面进行了代码控制,至此问题已解决(或者直接通过appOpMode和包名进行判断调用initiateInstall()函数也行,不建议),但是我们还得深入看下弹框做了什么动作。。。

 private void handleUnknownSources() {
        if (mOriginatingPackage == null) {
            Log.i(TAG, "No source found for package " + mPkgInfo.packageName);
            showDialogInner(DLG_ANONYMOUS_SOURCE);
            return;
        }

        Log.e(TAG, "wgd==No source found for package " + mPkgInfo.packageName);
        // Shouldn't use static constant directly, see b/65534401.
        //提前设置允许该应用获取未知来源权限
        if("com.ctg.itrdc.clouddesk".equals(mPkgInfo.packageName)){
            mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, mOriginatingUid,
            mPkgInfo.packageName, AppOpsManager.MODE_ALLOWED);
        }

        final int appOpCode =
                AppOpsManager.permissionToOpCode(Manifest.permission.REQUEST_INSTALL_PACKAGES);
        final int appOpMode = mAppOpsManager.noteOpNoThrow(appOpCode,
                mOriginatingUid, mOriginatingPackage);
       //根据appOpMode判断是否已获得未知来源安装权限   MODE_ERRORED没获取  MODE_ALLOWED已获取  
        switch (appOpMode) {
            case AppOpsManager.MODE_DEFAULT:
                mAppOpsManager.setMode(appOpCode, mOriginatingUid,
                        mOriginatingPackage, AppOpsManager.MODE_ERRORED);
                // fall through
            case AppOpsManager.MODE_ERRORED:
                showDialogInner(DLG_EXTERNAL_SOURCE_BLOCKED);
                break;
            case AppOpsManager.MODE_ALLOWED:
                initiateInstall();
                break;
            default:
                Log.e(TAG, "Invalid app op mode " + appOpMode
                        + " for OP_REQUEST_INSTALL_PACKAGES found for uid " + mOriginatingUid);
                finish();
                break;
        }
    }

4.showDialogInner(DLG_EXTERNAL_SOURCE_BLOCKED)弹框做了什么工作呢? 接下来调用了创建窗口函数createDialog()

 /**
     * Replace any dialog shown by the dialog with the one for the given {@link #createDialog id}.
     *
     * @param id The dialog type to add
     */
    private void showDialogInner(int id) {
        DialogFragment currentDialog =
                (DialogFragment) getFragmentManager().findFragmentByTag("dialog");
        if (currentDialog != null) {
            currentDialog.dismissAllowingStateLoss();
        }

        DialogFragment newDialog = createDialog(id);
        if (newDialog != null) {
            newDialog.showAllowingStateLoss(getFragmentManager(), "dialog");
        }
    }
 /**
     * Create a new dialog.
     *
     * @param id The id of the dialog (determines dialog type)
     *
     * @return The dialog
     */
    private DialogFragment createDialog(int id) {
        switch (id) {
            case DLG_PACKAGE_ERROR:
                return SimpleErrorDialog.newInstance(R.string.Parse_error_dlg_text);
            case DLG_OUT_OF_SPACE:
                return OutOfSpaceDialog.newInstance(
                        mPm.getApplicationLabel(mPkgInfo.applicationInfo));
            case DLG_INSTALL_ERROR:
                return InstallErrorDialog.newInstance(
                        mPm.getApplicationLabel(mPkgInfo.applicationInfo));
            case DLG_NOT_SUPPORTED_ON_WEAR:
                return NotSupportedOnWearDialog.newInstance();
            case DLG_INSTALL_APPS_RESTRICTED_FOR_USER:
                return SimpleErrorDialog.newInstance(
                        R.string.install_apps_user_restriction_dlg_text);
            case DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER:
                return SimpleErrorDialog.newInstance(
                        R.string.unknown_apps_user_restriction_dlg_text);
            case DLG_EXTERNAL_SOURCE_BLOCKED:
                //未知来源
                return ExternalSourcesBlockedDialog.newInstance(mOriginatingPackage);
            case DLG_ANONYMOUS_SOURCE:
                return AnonymousSourceDialog.newInstance();
        }
        return null;
    }
 /**
     * An error dialog shown when external sources are not allowed
     */
    public static class ExternalSourcesBlockedDialog extends AppErrorDialog {
        static AppErrorDialog newInstance(@NonNull String originationPkg) {
            ExternalSourcesBlockedDialog dialog = new ExternalSourcesBlockedDialog();
            dialog.setArgument(originationPkg);
            return dialog;
        }

        @Override
        protected Dialog createDialog(@NonNull CharSequence argument) {
            try {
                PackageManager pm = getActivity().getPackageManager();

                ApplicationInfo sourceInfo = pm.getApplicationInfo(argument.toString(), 0);

                return new AlertDialog.Builder(getActivity())
                        .setTitle(pm.getApplicationLabel(sourceInfo))
                        .setIcon(pm.getApplicationIcon(sourceInfo))
                        .setMessage(R.string.untrusted_external_source_warning)
                        .setPositiveButton(R.string.external_sources_settings,
                                (dialog, which) -> {
                                    Intent settingsIntent = new Intent();
                                    settingsIntent.setAction(
                                            Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
                                    final Uri packageUri = Uri.parse("package:" + argument);
                                    settingsIntent.setData(packageUri);
                                    try {
                                        getActivity().startActivityForResult(settingsIntent,
                                                REQUEST_TRUST_EXTERNAL_SOURCE);
                                    } catch (ActivityNotFoundException exc) {
                                        Log.e(TAG, "Settings activity not found for action: "
                                                + Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
                                    }
                                })
                        .setNegativeButton(R.string.cancel,
                                (dialog, which) -> getActivity().finish())
                        .create();
            } catch (NameNotFoundException e) {
                Log.e(TAG, "Did not find app info for " + argument);
                getActivity().finish();
                return null;
            }
        }
    }

 Intent settingsIntent = new Intent();

 settingsIntent.setAction(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);

 接下来主要看看是跳转到哪了,这其实调用到设置apk里面了。通过界面文字搜索最终定位到

/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java类

 最终发现设置打开应用“未知来源”权限执行了以下代码,至此得出第3步修改方案。

我们也可以按照下面进行初始化实现 

    private void openAppInstallUnknownSource(Context context){
        try {
            String packageName = SystemProperties.get("persist.sys.app_install_unknown_source");
            if(!android.text.TextUtils.isEmpty(packageName)){
                AppOpsManager mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
                PackageManager mPm = context.getPackageManager();
                PackageInfo mPackageInfo = mPm.getPackageInfo(packageName,
                    PackageManager.MATCH_DISABLED_COMPONENTS |
                    PackageManager.MATCH_ANY_USER |
                    PackageManager.GET_SIGNATURES |
                    PackageManager.GET_PERMISSIONS);
                mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
                mPackageInfo.applicationInfo.uid, packageName,AppOpsManager.MODE_ALLOWED);
            }
        }catch (Exception e) {
            Log.e(TAG, "Exception" + e);
        }
    }

修改方案2:

frameworks/base/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java

在private void grantDefaultSystemHandlerPermissions(int userId) 函数中添加如下代码:

 PackageParser.Package feedBackPackage = getPackage("net.sunniwell.dss");
            if (feedBackPackage != null
                && doesPackageSupportRuntimePermissions(feedBackPackage)) {
                    grantRuntimePermissions(feedBackPackage, STORAGE_PERMISSIONS, userId);
        } 

2.判断是否已获取未知来源权限

//getPackageManager()表示当前应用是否获得未知来源权限,一般用于自升级判断
boolean canRequestPackageInstalls = getPackageManager().canRequestPackageInstalls();
log.d("upgradech:canRequestPackageInstalls = " + canRequestPackageInstalls);

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 9.0 系统中,为了提高设备的安全性,禁止了默认情况下安装未知来源应用程序的权限。然而,我们可以通过编写代码来实现动态请求并获取该权限。 首先,在 AndroidManifest.xml 文件中添加以下权限: ```xml <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> ``` 然后,在你的应用程序中创建一个方法来请求安装未知来源应用程序的权限: ```java private void requestInstallUnknownAppsPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 判断当前 Android 版本是否高于等于 Android 8.0 if (!getPackageManager().canRequestPackageInstalls()) { // 如果没有权限,跳转到权限设置页面 Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, 1); } } } ``` 在该方法中,我们首先检查设备上的 Android 版本是否高于等于 Android 8.0,然后判断是否已经获得了安装未知来源应用程序的权限。如果没有权限,我们将启动一个意图(Intent)并跳转到权限设置页面,允许用户手动开启该权限。 最后,在你的代码中的适当位置调用该方法: ```java requestInstallUnknownAppsPermission(); ``` 这样一来,每当用户安装你的应用程序时,都会自动检查并请求安装未知来源应用程序的权限,如果没有权限则会跳转到权限设置页面,让用户手动开启。 注意:为了使这些代码生效,你需要确保你的应用程序具有 WRITE_EXTERNAL_STORAGE 权限,这样才能正常安装来自未知来源应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值