LOADING XQ STUDIO
logo

Android 7.0以上或以下 apk版本更新,下载之后自动安装

Android 6.0之前的

使用Intent 进行自动安装

        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri data = Uri.fromFile(apkFile);
        intent.setDataAndType(data, "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);

Android 7.0之后的

上面的代码在7.0的系统上会报下面的错误:


Caused by: android.os.FileUriExposedException

这是因为Android7.0系统提高了私有文件的安全性,访问私有文件目录被限制,此设置可防止私有文件的元数据泄漏,如它们的大小或存在性。

传递软件包网域外的 file:// URI 可能给接收器留下无法访问的路径。因此,尝试传递 file:// URI 会触发 FileUriExposedException。分享私有文件内容的推荐方法是使用 FileProvider。

先在配置文件中添加授权代码

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

1.定义一个FileProvider

<mainfest>
    ...
    <application>
        ...
        <!--用于7.0以上系统自动安装apk-->
        <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_provider"
                />
        </provider>
        ...
    </application>
    ...
 </mainfest>

2.添加可用权限的文件目录 

在res文件夹下创建xml文件夹,然后创建file_provider文件

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <!--升级-->
    <external-cache-path
 name="mn_update_external_cache"
 path="" />

    <cache-path
 name="mn_update_cache"
 path="" />
</paths>

注意:此处的filename(file_provider)与在manifest中provider的

android:resource="@xml/file_provider"

相对应。

3.代码中调用,调起安装

        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri data= FileProvider.getUriForFile(mContext, "com.laihui.pinche.fileProvider", apkFile);
        // 给目标应用一个临时授权
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(data, "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);

所以,为了适配,需要在调起apk进行安装时要增加判断,以下是完整代码,适配7.0之前和7.0之后

private void installAPk(File apkFile) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        //如果没有设置SDCard写权限,或者没有sdcard,apk文件保存在内存中,需要授予权限才能安装
        Uri data;
        // 判断版本大于等于7.0
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            // "net.csdn.blog.ruancoder.fileprovider"即是在清单文件中配置的authorities
            data = FileProvider.getUriForFile(mContext, "APP的applicationId.fileProvider", apkFile);
            // 给目标应用一个临时授权
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            data = Uri.fromFile(apkFile);
        }
        intent.setDataAndType(data, "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
}

注意:APP的applicationId如下:com.app.app名称、com.***.***.name 这样的格式。

注意测试监听报错:Failed to find configured root that contains /storage/emulated/0  是需要在file_provider文件添加如下代码

<root-path  name="my_image" path="."/>

整站搜索