【Android】轻松实现 APK 在线升级
APK 在线升级
APK 在线升级几乎是所有程序必备的功能。
在线升级功能能解决已有的问题并提供更丰富的新功能。
基本的流程是:
- 检测到新版本信息
- 弹出升级提示窗口
- 点击 No 不进行升级,完毕!
- 点击 Yes 后台下载升级程序
- 程序下载完成进入安装页面
- 安装成功,进入新程序
下面将介绍使用 UpdateAppUtil 实现在线升级功能
0. 需要权限
需要授权 android.permission.INTERNET,android.permission.WRITE_EXTERNAL_STORAGE 权限,具体申请版本在这里不展开了。
有兴趣的小伙伴可以看以往的文章。
1. 获取新版本信息
一般是访问服务器,获取新版本信息(以下面为例)
{
"url":"https://www.google.com/test/a670ef11/apk/test.apk",
"versionCode":1,
"versionName":"v2.1.0",
"create_time":"2019-12-14 03:44:34",
"description":"新增卫星链路,支持全球访问。"
}
必须要有 APK 的下载链接(url),版本号(versionCode)或者版本名(versionName)。
都是接下来需要用到的。
2. 设置信息
UpdateAppUtil.from(MainActivity.this)
.checkBy(UpdateAppUtil.CHECK_BY_VERSION_NAME) //更新检测方式,默认为VersionCode
.serverVersionCode(0)
.serverVersionName(version)
.updateInfo(description)
.apkPath(url)
.update();
字段 | 说明 |
---|---|
checkBy | 是否需要弹出升级提示的依据。CHECK_BY_VERSION_NAME 是根据 serverVersionName 的不同就弹出升级提示。CHECK_BY_VERSION_CODE 是根据 serverVersionCode 高于当前软件版本弹出升级提示。 |
serverVersionCode | 设置新软件的 versionCode (如示例的 1 ) |
serverVersionName | 设置新软件的 versionName (如示例的 “v2.1.0” ) |
updateInfo | 升级提示窗口显示的新软件描述 |
apkPath | 新软件下载链接(需要通过此链接下载新软件) |
update | 马上进行升级检查(如满足升级要求,弹出升级提示) |
isForce | 如果不选择升级,直接退出程序 |
3. 下载升级程序
Android 有多种框架可以下载程序(okhttp等),也可以开启一个线程去下载(IntentService)。
而 UpdateAppUtil 采用 Android SDK 提供的下载框架 DownloadManager,
public static void downloadWithAutoInstall(Context context, String url, String fileName, String notificationTitle, String descriptInfo) {
if (TextUtils.isEmpty(url)) {
Log.e(TAG, "url为空!!!!!");
return;
}
try {
Uri uri = Uri.parse(url);
Log.i(TAG, String.valueOf(uri));
DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(uri);
// 在通知栏中显示
request.setVisibleInDownloadsUi(true);
request.setTitle(notificationTitle);
request.setDescription(descriptInfo);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setMimeType("application/vnd.android.package-archive");
String filePath = null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//SD卡是否正常挂载
filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
} else {
Log.i(TAG, "没有SD卡" + "filePath:" + context.getFilesDir().getAbsolutePath());
return;
}
downloadUpdateApkFilePath = filePath + File.separator + fileName;
// 若存在,则删除
deleteFile(downloadUpdateApkFilePath);
Uri fileUri = Uri.parse("file://" + downloadUpdateApkFilePath);
request.setDestinationUri(fileUri);
downloadUpdateApkId = downloadManager.enqueue(request);
} catch (Exception e) {
e.printStackTrace();
}
}
request.setVisibleInDownloadsUi
下载UI显示到通知栏上
request.setTitle
设置通知栏的标题
request.setDescription
设置通知栏的消息
request.setNotificationVisibility
下载过程中一直显示下载信息,下载完后也存在(直到用户消除)
会清除没完成的文件,重新下载。
DownloadManager 下载过程中(下载完成)会发出广播,想要对下载完成进行处理需要监听广播。
(downloadUpdateApkFilePath 保存下载文件的路径,下载完成后可以通过此进行安装)
4. 进入安装
DownloadManager 下载完成后会发出 ACTION_DOWNLOAD_COMPLETE。
public class UpdateAppReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Cursor cursor = null;
try {
if (! intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
return;
}
if (DownloadAppUtil.downloadUpdateApkId <= 0) {
return;
}
long downloadId = DownloadAppUtil.downloadUpdateApkId;
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
cursor = manager.query(query);
if (cursor.moveToNext()) {
int staus = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
if (staus == DownloadManager.STATUS_FAILED) {
manager.remove(downloadId);
} else if ((staus == DownloadManager.STATUS_SUCCESSFUL)
&& (DownloadAppUtil.downloadUpdateApkFilePath != null)) {
Intent it = new Intent(Intent.ACTION_VIEW);
it.setDataAndType(Uri.parse("file://" + DownloadAppUtil.downloadUpdateApkFilePath),
"application/vnd.android.package-archive");
// todo 针对不同的手机 以及 sdk 版本, 这里的 uri 地址可能有所不同
it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(it);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
判断是 DownloadManager.ACTION_DOWNLOAD_COMPLETE 获取 APK 路径进行安装。