Android App更新安装APK

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

内容简介:一般地, 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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Letting Go of the Words

Letting Go of the Words

Janice (Ginny) Redish / Morgan Kaufmann / 2007-06-11 / USD 49.95

"Redish has done her homework and created a thorough overview of the issues in writing for the Web. Ironically, I must recommend that you read her every word so that you can find out why your customer......一起来看看 《Letting Go of the Words》 这本书的介绍吧!

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

各进制数互转换器

SHA 加密
SHA 加密

SHA 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试