如何在安卓 Oreo 中使用 PackageManager 的 canRequestPackageInstalls?

14

在我的应用清单文件中,我已经声明了使用该权限:

    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

在我的代码中,我检查我的应用是否可以从未知来源安装:

    public void reinstallApp(Activity activity, String pathname, int request_code)
    {
        if (activity.getPackageManager().canRequestPackageInstalls())
        {
            try
            {
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setDataAndType(Uri.fromFile(new File(pathname)), "application/vnd.android.package-archive");
                activity.startActivityForResult(intent, request_code);
            }
            catch (Exception e)
            {
                LogUtilities.show(this, e);
            }
        }
        else
        {
            activity.startActivity(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(Uri.parse(String.format("package:%s", activity.getPackageName()))));
        }
    }

即使我在选择活动中检查了允许从未知来源安装,但 "activity.getPackageManager().canRequestPackageInstalls()" 总是返回 "false"。问题出在哪里?

2个回答

23

你必须先请求权限。为此,您需要从未知来源调用安装权限。我只是通过重新排列您的代码来获得答案。

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (!getPackageManager().canRequestPackageInstalls()) {
                startActivityForResult(new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).setData(Uri.parse(String.format("package:%s", getPackageName()))), 1234);
            } else {
                callInstallProcess();
            }
        } else {
            callInstallProcess();
        }

以上代码将会在你的onCreate()方法中。然后你可以验证结果。

@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1234 && resultCode == Activity.RESULT_OK) {
        if (getPackageManager().canRequestPackageInstalls()) {
            callInstallProcess();
        }
    } else {
        //give the error
    }
}

在 callInstallProcess() 函数中安装将会发生的位置。

        try
        {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(new File(pathname)), "application/vnd.android.package-archive");
            activity.startActivityForResult(intent, request_code);
        }
        catch (Exception e)
        {
            LogUtilities.show(this, e);
        }

不要忘记在AndroidManifest.xml中给予权限

    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

当我使用你的callInstallProcess()方法时,我会得到一个异常:exposed beyond app through Intent.getData()。我认为这是因为.apk文件包含在我的应用程序中,而其他活动无法访问我的文件。 - Zdravko Donev
注意:如果在代码片段中,将startActivityForResult(...)替换为getActivity()。 startActivityForResult(...)以便在onActivityResult中获得正确的requestCode。 - Duna
1
@ZdravkoDonev,您需要使用FileProvider。 - Ishaan Kumar
当我调用getPackageManager().canRequestPackageInstalls()时,我会收到Java.Lang.SecurityException: '需要声明android.permission.REQUEST_INSTALL_PACKAGES以调用此API' - Oiproks

5
根据这里所述,为了使getPackageManager().canRequestPackageInstalls()正常工作,您必须声明此权限。
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

在您的AndroidManifest.xml中,就像您已经做过的一样,请声明build.gradle或AndroidManifest.xml中的targetSdkVersion为26或更高版本(换句话说,您的应用程序必须针对Android Oreo或更高版本进行定位),这很可能是您问题的原因。
否则,即使用户授予了权限,该方法也将始终返回false

我正在处理一个旧项目,targetSdkVersion 起了作用! - Petrus
targetSdkVersion 保住了我。 - GAMA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接