Android升级更新及相关知识

前言:

检测是否需要更新,这个很简单,这里就不叙述了。本文主要介绍如何下载和安装更新。下载新的安装包,大致有三种方式:自己写一个下载器、使用安卓自带的下载管理器、使用浏览器下载。其中,利用安卓自带下载管理器较为方便而不失优雅,本人的项目中使用较多。

下载器

自己写下载器

下载器的写法可以参照《第一行代码》中“服务的最佳实践”。郭神采用了前台服务,但是国内安卓手机使用前台服务容易出问题,需要稍微修改下,可以参照网上的方法。此外,也可以将其改为后台服务和普通通知。下载完成时,触发安装过程即可。

前台的修改可参考:Android startForeground 却无notification的黑科技原理分析 以及Android7.1的修复

 

使用下载管理器

调用DownloadManager和DownloadManager.Request,后者用来设置具体的参数,最后通过调用

downloadManager.enqueue(request)将其加入下载队列。具体参照一下代码(感谢:某位前辈)。

import android.app.DownloadManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;

public class DownloadAppUtils {
    private static final String TAG = DownloadAppUtils.class.getSimpleName();
    public static long downloadUpdateApkId = -1;//下载更新Apk 下载任务对应的Id
    public static String downloadUpdateApkFilePath;//下载更新Apk 文件路径

    /**
     * 下载更新apk包
     * 权限:1,<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
     * @param context
     * @param url
     */
    public static void downloadForAutoInstall(Context context, String url, String fileName, String title) {
        if (TextUtils.isEmpty(url)) {
            return;
        }
        try {
            Uri uri = Uri.parse(url);
            DownloadManager downloadManager = (DownloadManager) context
                    .getSystemService(Context.DOWNLOAD_SERVICE);
            DownloadManager.Request request = new DownloadManager.Request(uri);
            //在通知栏中显示
            request.setVisibleInDownloadsUi(true);
            request.setTitle(title);
            String filePath = null;
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  //外部存储卡
                filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
            } else {
                Log.i(TAG,"没有SD卡");
                return;
            }

            downloadUpdateApkFilePath = filePath + File.separator + fileName;
            // 若存在,则删除
            deleteFile(downloadUpdateApkFilePath);
            Uri fileUri = Uri.fromFile(new File(downloadUpdateApkFilePath));

            request.setDestinationUri(fileUri);
            downloadUpdateApkId = downloadManager.enqueue(request);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
//            registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
        }
    }


    private static boolean deleteFile(String fileStr) {
        File file = new File(fileStr);
        return file.delete();
    }
}

使用浏览器下载

创建一个URI的Intent,用来开启新的活动,由于该活动需要离开本程序,所以需标记Intent.FLAG_ACTIVITY_NEW_TASK。

/**
     * 通过浏览器下载APK包
     * @param context
     * @param url
     */
    public static void downloadForWebView(Context context, String url) {
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

 

自动安装APK文件

这部分比较麻烦,6.0和7.0都有过些变更,所以网上的方法未必适用。本人在这里走了不少弯路,这里先贴出7.0以上版本的写法。(注意,这些安装过程需要在下载完后自动安装,因此可以设置一个广播监听或者下载监听)

File file = new File(DownloadAppUtils.downloadUpdateApkFilePath);
Intent install = new Intent();
install.setAction(Intent.ACTION_VIEW);
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri uri = FileProvider.getUriForFile(MyApplication.getContext(), "com.fanjin.rctrandom.provider", file);
install.setDataAndType(uri, "application/vnd.android.package-archive");
context.startActivity(install);

此外还需要在AndroidManifest.xml中添加如下代码。

        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.fanjin.rctrandom.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>

以及新建一个xml/provider_paths.xml。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <root-path name="root_path" path="." />
    <external-path name="external_files" path="."/>
</paths>

以上部分是试错踩坑很久之后才成功的,出现过很多错误,比如

FileUriExposedException

ActivityNotFoundException: No Activity found to handle Intent

IllegalArgumentException: Failed to find configured root that contains

以及“解析软件包时出现问题”等。

其中解析包出现问题,调试很久之后发现是权限问题(不具备执行权限),试过很多方法,然而最终由一行代码解决:

install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

其中的linux命令法不起作用,大概也是命令权限不够吧。但是也算是学到了如何在安卓代码里执行linux命令,在此记一笔:

String[] command = {"chmod", "777", "/mnt/sdcard/rctrandom/rctrandom.apk" };
ProcessBuilder builder = new ProcessBuilder(command);
try {
     builder.start();
} catch (IOException e) {
     e.printStackTrace();
}

可参考:安卓程序中调用 linux 命令

 

以上只是针对7.0以上版本的更新方式,实际操作时需要考虑各种版本的兼容问题。

 

鸣谢

需要感谢许多博客资料:

android app 更新下载安装 适配android 7.0(非常棒的总结!)

Android实现APP在线下载更新

Android检查更新下载安装

Android:使用 DownloadManager 进行版本更新,出现 No Activity found to handle Intent 及解决办法

FileProvider相关 Failed to find configured root that contains

android 7.0 因为file://引起的FileUriExposedException异常

安卓7.0遇到 android.os.FileUriExposedException: file:///storage/emulated.. exposed beyond app through Intent.getData()

android.os.FileUriExposedException: file:///sdcard/ beyond app through

获取未安装的APK图标、版本号、包名、名称、是否安装、安装、打开

Android 7.0解析包时出现问题 的解决方案(应用内更新)

更新应用程序安卓apk时出现解析程序包时出现问题

android 程序打开第三方程序(以后别的地方说不定有用)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FarmerJohn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值