Android App更新安装APK

栏目: IOS · Android · 发布时间: 6年前

内容简介:一般地, Android App 都会被要求在App内进行软件更新提示, 让用户下载apk文件, 然后更新安装新版本, 一般过程如下:通常我们将apk文件存放在外部存储上.然后将 文件路径传递给系统, 进行apk的安装.安装代码如下:

概要

一般地, Android App 都会被要求在App内进行软件更新提示, 让用户下载apk文件, 然后更新安装新版本, 一般过程如下:

  1. 检测是否有新版本
  2. 下载新版本app apk文件
  3. 安装新的apk

通常我们将apk文件存放在外部存储上.然后将 文件路径传递给系统, 进行apk的安装.

文件路径传递过程

安装代码如下:

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

通常情况下这样没问题, 但是在Android7.0 系统上会出现异常 FileUriExposedException , 这是因为在7.0 系统上发生的权限变更:

系统权限更改

为了提高私有文件的安全性,面向 Android 7.0 或更高版本的应用私有目录被限制访问(0700)。此设置可防止私有文件的元数据泄漏,如它们的大小或存在性。此权限更改有多重副作用:

私有文件的文件权限不应再由所有者放宽,为使用 MODE_WORLD_READABLE 和/或 MODE_WORLD_WRITEABLE 而进行的此类尝试将触发 SecurityException。

注:迄今为止,这种限制尚不能完全执行。应用仍可能使用原生 API 或 File API 来修改它们的私有目录权限。但是,我们强烈反对放宽私有目录的权限。

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

DownloadManager 不再按文件名分享私人存储的文件。旧版应用在访问 COLUMN_LOCAL_FILENAME 时可能出现无法访问的路径。面向 Android 7.0 或更高版本的应用在尝试访问 COLUMN_LOCAL_FILENAME 时会触发 SecurityException。通过使用 DownloadManager.Request.setDestinationInExternalFilesDir() 或 DownloadManager.Request.setDestinationInExternalPublicDir() 将下载位置设置为公共位置的旧版应用仍可以访问 COLUMN_LOCAL_FILENAME 中的路径,但是我们强烈反对使用这种方法。对于由 DownloadManager 公开的文件,首选的访问方式是使用ContentResolver.openFileDescriptor()。

上述说明在7.0 系统上使用新的 API 来进行文件传递.

Android 7.0 的文件传递

官方推荐使用 FileProvider , 那我们看看如何使用

1. 在 Manifest 文件添加 provider, 如下:

<manifest>
    ...
    <application>
        ...
        <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/provider_paths"/>
        ...
    </application>
</manifest>

添加 provider

2. 设置文件路径

res/ 目录下创建 xml 文件夹, 然后穿件文件 provider_paths.xml , 其内容格式如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <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="" />
        <external-media-path name="external_media_path" path="" />
    </paths>
</resources>

指定的路径有6中,其中:

<files-path name="name" path="path" />

代表你的app内部存储区域 files/ 目录下的文件, 等同于 Context.getFilesDir() .

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

代表你的app内部存储区域 files/ 目录下的文件, 等同于 Context.getCacheDir() .

<external-path name="name" path="path" />

代表外部存储根目录下的文件路径, 等同于 Environment.getExternalStorageDirectory() .

<external-files-path name="name" path="path" />

代表你的app外部存储区域根木目录下的路径, 等同于 Context#getExternalFilesDir(String) Context.getExternalFilesDir(null)

<external-cache-path name="name" path="path" />

代表你的app外部存储区域缓存目录下的路径, 等同于 Context.getExternalCacheDir()

<external-media-path name="name" path="path" />

代表你的app外部存储区域媒体目录下的路径, 等同于 Context.getExternalMediaDirs()

根据自己的需要,设置路径.

3. 代码中使用FileProvider

Uri contentUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", newApk);

这样可以将 Uri 进行传递.

安装过程

一般我们直接将apk路径传递给系统进行安装, 如上面的代码:

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

但是在 Android8.0 又有权限变更, 需要单独的安装权限:

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

所以当在 8.0及以上的系统安装apk是还需添加此权限到 Manifest 文件, 并做判断.

private void checkInstallApkPermission(String filePath) {
    L.i(TAG, "checkInstallApkPermission:" + filePath);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        if (getPackageManager().canRequestPackageInstalls()) {
            L.i(TAG, "can request package");
            launchUpgrade(new File(filePath));
        } else {
            L.i(TAG, "can not request package");
            launchUpgrade(new File(filePath));
        }
    } else {
        launchUpgrade(new File(filePath));
    }
}

可能会有人疑惑, 这里为什么if else 都是直接 启动升级安装?

因为目前国内的定制系统会已经添加授权弹窗, 如果你采用网络所说的直接跳到 Setting界面, 让用户手动选择是比较麻烦的, 如果直接调用安装, 则系统会弹窗提示.

原创文章, 转载请说明出处~


以上所述就是小编给大家介绍的《Android App更新安装APK》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

A=B

A=B

Marko Petkovsek、Herbert S. Wilf、Doron Zeilberger / AK Peters, Ltd. / 1996-01 / USD 49.00

At some point, this book describes methods of solving the problem raised by Donald E. Knuth in the classical book "The Art of Computer Programming, Volume 1: Fundamental Algorithms". The main purpo......一起来看看 《A=B》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具