安卓8.0下的应用安装

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/alex01550/article/details/82184232

目录

那么如何处理这个权限呢?

1.应用的安装流程

2.首先申请权限

3.点击按钮进行应用安装

4.检查是否有未知应用来源的权限

5.执行安装流程

到这里就基本就完了,但有几个注意点:


前言:安卓系统升级到8.0之后,Google将未知应用安装权限的开关除掉了(原先打开这个开关所有的应用都会授予此权限),取而代之的是未知来源应用的管理列表,需要在里面打开每个应用的未知来源的安装权限。如果不处理这个未知来源的权限,那么将会阻塞内部应用启动安装过程,会导致应用根本无法更新,只能去应用市场重新下载。


那么如何处理这个权限呢?

1.应用的安装流程

1.先说说8.0之前的安装流程:

从服务器下载应用到本地 >>开启安装应用代码>>安装完成

2.  8.0之后应用安装流程:

从服务器下载应用到本地 >>代码打开安装位置来源应用界面>>授予权限>>开启安装应用代码>>安装完成

其中 “代码打开安装位置来源应用界面”会阻塞安装应用过程只有授予了安装未知应用的权限,才能继续执行安装过程。

3.为了模拟从网络上下载应用更新,我直接在内部存储放置了一个应用,点击安装,直接执行8.0的安装流程。

2.首先申请权限

    <!--读写内部存储权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <!--8.0安卓 软件安装需要申请的权限-->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

处理sdcard读取权限,代码如下:

 @TargetApi(Build.VERSION_CODES.M)
    private void checkSdCardPermission() {
        if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            installApk();
        } else {
            requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 100);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100 & grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            installApk();
        }
    }
重点是该权限:<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

3.点击按钮进行应用安装

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn_install).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_install:
                checkInstallPermissionAndInstall();
                break;
        }
    }

代码很简单,一个执行安装的按钮

4.检查是否有未知应用来源的权限

 public void checkInstallPermissionAndInstall() {
        // 如果是8.0系统
        if (Build.VERSION.SDK_INT >= 26) {
            boolean b = getPackageManager().canRequestPackageInstalls();
            // 如果已经打开了安装未知来源的开关
            if (b) {
                checkSdCardPermission();
            } else {
                // 请求打开安装未知应用来源的界面,非运行时权限
                Uri packageURI = Uri.parse("package:" + getPackageName());
                Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageURI);
                startActivityForResult(intent, GET_UNKNOWN_APP_SOURCES);
            }
        } else {
            checkSdCardPermission();
        }
    }

注释很清楚,这里只说重点:boolean b = getPackageManager().canRequestPackageInstalls();该行代码检查是否有未知应用来源的权限,如果有直接安装,没有就打开未知应用来源的界面。注意,这和运行时权限的申请是不同的!(很多人把运行时权限搞混了!)或者直接在清单文件中添加权限:

<!--安卓8.0打开apk安装更新-->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

那么就不需要检查未知来源权限了,直接执行installApk方法

在onActivityResult()中处理回调结果,代码如下:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case GET_UNKNOWN_APP_SOURCES:
                // 用户授予了未知来源应用的权限
                if (resultCode == RESULT_OK) {
                    checkSdCardPermission();
                }
                break;
            default:
                break;
        }
    }

5.执行安装流程

执行安装代码:

private void installApk() {
        Uri uri = null;
        File file = new File(downLoadUrl);
        if (!file.exists()) {
            ToastUtil.showToast("文件不存在!");
            return;
        }
        // 安卓7.0及以上
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(this, getApplicationInfo().packageName + ".FileProvider", file);
        } else {
            uri = Uri.fromFile(file);
        }
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        startActivity(intent);
    }

这里需要说的是,intent.setDataAndType(uri, "application/vnd.android.package-archive");中uri这个参数,同样需要对7.0及以上的系统进行适配,需要设置provider。

我是将应用直接放在了根目录下:

 private static final String downLoadUrl = Environment.getExternalStorageDirectory() + "/app-debug.apk";

provider配置如下:

        <!--安卓7.0及以上需配置provider -->
        <provider
            android:name="android.support.v4.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_public" />
        </provider>

 file_paths_public.xml 文件内容如下:

<paths>
    <!--指定共享的文件夹范围-->
    <external-path
        name="external_storage_root"
        path="." />
</paths>

path="." 表示内部存储的根目录

关于provider的配置,可以参见:https://blog.csdn.net/alex01550/article/details/82115074

中provider部分介绍,这里不再赘述。

到这里就基本就完了,但有几个注意点:

1.从内部存储安装应用需要sdcard运行时权限,如果没有该权限会提示解析错误!

2.启动安装界面时 intent.setDataAndType(uri, "application/vnd.android.package-archive"),中uri要记得做7.0适配!

3.在测试apk时,放在内部存储目录的apk,要通过build>>Build Apk(s) 进行构建,否则安装时会提示应用未安装!见下图

所以当你决定要适配到8.0的时候,一定要做其他方面的适配!
 

展开阅读全文

没有更多推荐了,返回首页