4

Android 开发:apk文件的安装6.0,7.0,8.0踩坑笔记

 3 years ago
source link: http://www.androidchina.net/10146.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

最近在做 APP 的升级功能,需要在 apk 文件下载下来之后安装,我本以为是个很简单的功能,直接调用系统的接口就完事了,没想到还是有不少坑的。

Android 6.0 版本的安装

这个最常规,在6.0版本及之前版本都是通用的。

/**
 * 安装apk
 *
 * @param
 */
public static void install(Context mContext, File file) {
    Intent install = new Intent(Intent.ACTION_VIEW);
    install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
    mContext.startActivity(install);
}

Android 7.0 版本的安装

上面的代码在 Android 7.0 及以上版本安装 apk 则会遇到 android.os.FileUriExposedException 问题。官方给出的解释是:

对于面向 Android 7.0 的应用,Android 框架执行的 StrictMode API 政策禁止在您的应用外部公开 file:// URI。如果一项包含文件 URI 的 intent 离开您的应用,则应用出现故障,并出现 FileUriExposedException 异常。

解决方案如下:

1.在 AndroidManifest.xml 中添加如下代码:

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="你的包名.fileProvider"
            android:grantUriPermissions="true"
            android:exported="false">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>

注意

authorities:你app的包名.fileProvider
grantUriPermissions:必须是true,表示授予 URI 临时访问权限
exported:必须是false
resource:中的@xml/file_paths是我们接下来要添加的文件

还有额外的坑☠️

我在使用过程中添加以上 provider 代码之后,遇到了 manifest 合并冲突问题:

Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed with multiple errors, see logs

解决方案:由于多个lib库中定义类相同所以冲突,集成FileProvider重写个类即可。没有遇到此问题则可以略过。代码如下:

public class InstallApkProvider extends FileProvider {
}

所以我在 Manifest 中添加的代码如下:

<provider
    android:name=".InstallApkProvider"
    android:authorities="我的包名.fileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

2.在res/xml下新建file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <root-path name="root" path="" />
        <files-path name="files" path="" />
        <cache-path name="cache" path="" />
        <external-path name="external" path="" />
        <external-files-path name="external_file_path" path="" />
        <external-cache-path name="external_cache_path" path="" />
    </paths>
</resources>
path:需要临时授权访问的路径
name:就是你给这个访问路径起个名字
复制代码

3.Android 7.0 的构建 Uri 在6.0时代,直接使用 Uri.fromFile(apkFile)构建出一个Uri,现在我们使用

FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);

BuildConfig.APPLICATION_ID 直接是应用的包名。

到这里,我们就可以愉快的在7.0上安装 apk 了。代码如下:

    /**
     * 安装apk
     *
     * @param
     */
    public static void install(Context mContext, File file) {
        Intent install = new Intent(Intent.ACTION_VIEW);
        install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(mContext, "com.skycar.vehicleassistor.fileProvider", file);

            install.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
        mContext.startActivity(install);
    }

Android 8.0 版本的安装

如果你的系统版本是 8.0+,那你需要多加一个权限,否则还是不行滴!

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

就这样,我们完全搞定了 apk 文件在不同 Android 版本系统上的安装。撒花

作者:Rickon
链接:https://juejin.im/post/5da568f25188251189134a27
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转载请注明:Android开发中文站 » Android 开发:apk文件的安装6.0,7.0,8.0踩坑笔记


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK