You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Android Oreo(8.0)中管理未知来源应用安装?

刚好之前踩过Android 8.0未知来源安装适配的坑,整理了完整的用户侧变化和开发者适配流程,希望能帮到你:

Android Oreo(8.0)未知来源应用安装的核心变化与开发者适配指南

一、用户视角的安装方式变化

Android 8.0对「未知来源应用」的安装逻辑做了根本性调整:

  • 8.0之前:只需全局开启系统设置中的「未知来源」开关,就能安装所有第三方APK
  • 8.0及以后移除全局开关,改为针对单个应用授予安装权限——用户安装某应用的APK时,会被引导到系统设置页面,给该应用单独开启「允许来自此来源的应用」权限,授权后才能完成安装

二、开发者视角的完整权限获取与安装流程

这部分是适配的核心,步骤如下:

1. 在Manifest中声明必要权限

首先需要添加安装权限的声明:

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

2. 检查当前应用是否已拥有安装权限

在触发安装前,先判断应用是否具备安装未知应用的权限,根据结果分支处理:

// 定义请求码
private static final int REQUEST_CODE_INSTALL_PERMISSION = 1001;

private void checkInstallPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        boolean hasPermission = getPackageManager().canRequestPackageInstalls();
        if (!hasPermission) {
            // 无权限,跳转到系统设置页面申请
            Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
            intent.setData(Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, REQUEST_CODE_INSTALL_PERMISSION);
        } else {
            // 已有权限,直接执行安装逻辑
            startInstallApk();
        }
    } else {
        // 8.0以下版本,直接执行安装(前提是用户已开启全局未知来源)
        startInstallApk();
    }
}

3. 处理权限申请的回调结果

onActivityResult中接收用户的授权结果(如果使用Jetpack的Activity Result API,写法会更简洁):

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_CODE_INSTALL_PERMISSION) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            boolean hasPermission = getPackageManager().canRequestPackageInstalls();
            if (hasPermission) {
                // 用户授权成功,启动安装
                startInstallApk();
            } else {
                // 用户拒绝授权,给出提示
                Toast.makeText(this, "未授予安装权限,无法完成应用安装", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

4. 执行APK安装的通用逻辑

完成权限校验后,就可以执行安装操作,注意适配7.0+的FileProvider要求:

private void startInstallApk() {
    // 示例:获取下载目录下的APK文件
    File apkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "target_app.apk");
    Intent installIntent = new Intent(Intent.ACTION_VIEW);
    installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        // 7.0及以上需要用FileProvider获取URI
        Uri apkUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", apkFile);
        installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive");
    } else {
        installIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
    }

    startActivity(installIntent);
}

补充:FileProvider的配置(7.0+必备)

在Manifest中添加FileProvider声明:

<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="${applicationId}.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

然后在res/xml目录下创建file_paths.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 对应上述代码中的下载目录 -->
    <external-files-path name="download" path="Download/" />
</paths>

如果开发者未做以上适配,在8.0+设备上直接触发安装会导致失败,甚至抛出异常,所以务必按流程完成权限申请与适配。

内容的提问来源于stack exchange,提问作者Patneu

火山引擎 最新活动