版本更新一般分两种情况:
- 需要更新时跳转到应用市场或者跳转到浏览器处理
- 另一种情况则是在App内进行更新
第一种没什么好说的,本文主要是实现应用内进行更新
App内部更新分以下几个步骤:
- 检测App版本
- 下载Apk
- 安装已下载完成的Apk
下面贴上实例:
1. 检测App版本
/**
* 登录时查询是否有新版本应用
*/
public void queryVersion() {
if (!Const.IS_CHECK_UPDATE) return; // 判断是否进行请求更新 (场景:进入App自动检测更新)
HttpUtil.post(mContext, Const.URL_UPDATE, new TextResponseHandler() {
@Override
public void onSuccess(String result) {
// 解析服务器返回的版本信息
JSONObject jsonObject = JSON.parseObject(result);
if (Const.JSON_SUCCESS.equals(jsonObject.getString("success")))
{
String strResult = jsonObject.getString("isupdate");
if (TextUtils.isEmpty(strResult)) return;
UpdateVersion update = JSON.parseObject(strResult, UpdateVersion.class);
String edition = update.getEdition(); // 服务器返回版本信息
String versionName = AppUtil.getVersionName(mContext); // 当前应用版本号
// 比较两者 不一致提示更新
if (!versionName.equals(edition))
{
// 显示更新提示
showNoticeDialog(update, versionName);
}
}
}
@Override
public void onFailure(String message) // 视业务而定
{
...
}
});
}
2.有新版本时 提示更新
/**
* 显示软件更新对话框
*
* @param update 更新介绍
* @param versionName 当前版本名
*/
private void showNoticeDialog(final UpdateVersion update, String versionName)
{
// 构造对话框
MaterialDialog.Builder builder = new MaterialDialog.Builder(mContext);
builder.title("更新提示");
if ("1".equals(update.getCode())) // 强制更新
builder.content("您当前使用版本会对您的使用带来不便,请您更新!");
else
builder.content("当前版本:" + versionName + "\r\n新版本:" + update.getEdition()); // 非重要更新
builder.positiveText("确定");
builder.negativeText("取消");
//点击事件添加 方式1
builder.onAny(new MaterialDialog.SingleButtonCallback()
{
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which)
{
if (which == DialogAction.POSITIVE)
{
dialog.dismiss();
showDownloadProgress(update); // 显示更新进度 同时进行更新
} else if (which == DialogAction.NEGATIVE)
{
if ("2".equals(update.getCode()) || "3".equals(update.getCode()))
{
dialog.dismiss();
}else // 强制更新 如果不进行更新则无法使用当前应用
{
dialog.dismiss();
mContext.finish();
System.exit(0);
}
}
}
});
MaterialDialog materialDialog = builder.build();
materialDialog.setCancelable(false);
materialDialog.show();
}
3.显示下载进度
/**
* 显示软件下载提示框
*
* @param update 后台返回更新的信息
*/
private void showDownloadProgress(UpdateVersion update) {
String url = update.getUrl();
apkName = url.substring(url.lastIndexOf("/") + 1, url.length());
String apkUrl = Const.URL_HOSTS + url;
// 构造软件下载对话框
if (materialDialog == null)
{
materialDialog = new MaterialDialog.Builder(mContext)
.title("版本升级")
.content("正在下载安装包,请稍候")
.progress(false, 100, false)
.cancelable(false)
.show();
}
downloadThread(apkUrl); // 下载Apk
}
4.下载Apk
/**
* 使用DownloadManager进行下载
*/
private void downloadThread(String apkUrl)
{
downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);
//设置显示在文件下载Notification(通知栏)中显示的文字。6.0的手机Description不显示
request.setTitle(mContext.getString(R.string.app_name));
request.setDescription("新版本给您带来更优质的体验!");
request.setMimeType("application/vnd.android.package-archive");
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
request.allowScanningByMediaScanner();
request.setVisibleInDownloadsUi(true);
lastDownloadId = downloadManager.enqueue(request);
downloadObserver = new DownloadChangeObserver(null);
mContext.getContentResolver().registerContentObserver(CONTENT_URI, true, downloadObserver);
}
5.监听下载进度
class DownloadChangeObserver extends ContentObserver {
DownloadChangeObserver(Handler handler)
{
super(handler);
}
@Override
public void onChange(boolean selfChange)
{
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(lastDownloadId);
DownloadManager dManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
Cursor cursor = null;
try
{
cursor = dManager.query(query);
if (cursor != null && cursor.moveToFirst())
{
final int totalColumn = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
final int currentColumn = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
int totalSize = cursor.getInt(totalColumn);
int currentSize = cursor.getInt(currentColumn);
float percent = (float) currentSize / (float) totalSize;
int progress = Math.round(percent * 100);
materialDialog.setProgress(progress);
if (progress == 100)
{
materialDialog.dismiss();
installAPK();
}
}
} finally
{
// 一定不要忘记关闭游标!!!
if (cursor != null)
{
cursor.close();
}
}
}
}
6.安装新版Apk
private void installAPK() {
File apkFile =new File
(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), apkName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
{
Uri apkUri = FileProvider.getUriForFile(mContext, "com.你的自定义路径.update.fileprovider", apkFile);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else
{
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
mContext.startActivity(intent);
}
7.释放资源
/**
* 释放当前资源
*/
public void onDestroy()
{
if (Const.IS_CHECK_UPDATE && downloadManager != null)
{
downloadManager = null;
mContext.getContentResolver().unregisterContentObserver(downloadObserver);
}
}
结束了?No No No ,由于Android系统的不断完善,尤其是权限方面,所以在7.0以上的系统需要在manifest中注册provider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.你的路径.update.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- file_paths -->
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<external-path
name="download"
path=""/>
</paths>
</resources>
ok,至此自动App更新功能完成
功能全部代码:
public class UpdateManager {
private DownloadChangeObserver downloadObserver;
private long lastDownloadId = 0;
//"content://downloads/my_downloads"必须这样写不可更改
private final Uri CONTENT_URI = Uri.parse("content://downloads/my_downloads");
private AlertDialog materialDialog;
private Activity mActivity;
private String apkName;
private DownloadManager downloadManager;
public UpdateManager(Activity activity)
{
this.mActivity = activity;
}
/**
* 登录时查询是否有新版本应用
*/
public void queryVersion() {
if (!Constants.IS_CHECK_UPDATE) return;
HttpUtil.get(mActivity, Constants.URL_UPDATE, new TextResponseHandler() {
@Override
public void onSuccess(String result)
{
JSONObject jsonObject = JSON.parseObject(result);
if (Constants.JSON_SUCCESS.equals(jsonObject.getString("success")))
{
String strResult = jsonObject.getString("isupdate");
if (TextUtils.isEmpty(strResult)) return;
UpdateVersion update = JSON.parseObject(strResult, UpdateVersion.class);
String edition = update.getEdition();
String versionName = AppUtil.getVersionName(mContext);
String code = update.getCode();
if (!versionName.equals(edition))
{
showNoticeDialog(update, versionName);
}
}
}
@Override
public void onFailure(String message)
{
...
}
});
}
/**
* 显示软件更新对话框
*
* @param update 更新介绍
* @param versionName 当前版本名
*/
private void showNoticeDialog(final UpdateVersion update, String versionName)
{
// 构造对话框
MaterialDialog.Builder builder = new MaterialDialog.Builder(mContext);
builder.title("系统提示");
if ("1".equals(update.getCode())) // 强制更新
builder.content("您当前使用版本会对您的使用带来不便,请您更新!");
else // 正常更新
builder.content("当前版本:" + versionName + "\r\n新版本:" + update.getEdition());
builder.positiveText("确定");
builder.negativeText("取消");
builder.onAny(new MaterialDialog.SingleButtonCallback()
{
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which)
{
if (which == DialogAction.POSITIVE)
{
dialog.dismiss();
showDownloadProgress(update);
} else if (which == DialogAction.NEGATIVE)
{
if ("2".equals(update.getCode()) || "3".equals(update.getCode()))
{
dialog.dismiss();
}else // 强制更新
{
dialog.dismiss();
mContext.finish();
System.exit(0);
}
}
}
});
MaterialDialog materialDialog = builder.build();
materialDialog.setCancelable(false);
materialDialog.show();
}
/**
* 显示软件下载对话框
*
* @param update 返回更新信息
*/
private void showDownloadProgress(UpdateVersion update)
{
String url = update.getUrl();
apkName = url.substring(url.lastIndexOf("/") + 1, url.length());
String apkUrl = Constants.URL_HOSTS + url;
// 构造软件下载对话框
if (materialDialog == null)
{
materialDialog = new MaterialDialog.Builder(mActivity)
.title("版本升级")
.content("正在下载安装包,请稍候")
.progress(false, 100, false)
.cancelable(false)
.show();
}
// 屏幕常亮
mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
downloadThread(apkUrl); // 下载
}
private void downloadThread(String apkUrl)
{
String directoryDownloads = Environment.DIRECTORY_DOWNLOADS;
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
// ToolUtil.deleteFile(path + "/" + apkName); // 删除下载的安装包
downloadManager = (DownloadManager) mActivity.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
request.setDestinationInExternalPublicDir(directoryDownloads, apkName);
//设置显示在文件下载Notification(通知栏)中显示的文字。6.0的手机Description不显示
request.setTitle(mActivity.getString(R.string.app_name));
request.setDescription("新版本给您带来更优质的体验!");
request.setMimeType("application/vnd.android.package-archive");
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
request.allowScanningByMediaScanner();
request.setVisibleInDownloadsUi(true);
lastDownloadId = downloadManager.enqueue(request);
downloadObserver = new DownloadChangeObserver(null);
mActivity.getContentResolver().registerContentObserver(CONTENT_URI, true, downloadObserver);
}
//用于显示下载进度
class DownloadChangeObserver extends ContentObserver {
DownloadChangeObserver(Handler handler)
{
super(handler);
}
@Override
public void onChange(boolean selfChange)
{
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(lastDownloadId);
DownloadManager dManager = (DownloadManager) mActivity.getSystemService(Context.DOWNLOAD_SERVICE);
Cursor cursor = null;
try
{
assert dManager != null;
cursor = dManager.query(query);
if (cursor != null && cursor.moveToFirst())
{
//下载的文件到本地的目录
String addressDir = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
final int totalColumn = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
final int currentColumn = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
int totalSize = cursor.getInt(totalColumn);
int currentSize = cursor.getInt(currentColumn);
float percent = (float) currentSize / (float) totalSize;
int progress = Math.round(percent * 100);
materialDialog.setProgress(progress);
if (progress == 100)
{
materialDialog.dismiss();
installAPK();
}
}
} finally
{
if (cursor != null)
{
cursor.close();
}
}
}
}
/*
// 使用浏览器下载
private void openBrowserDown(UpdateVersion update)
{
String apkUrl = Constants.URL_HOSTS + update.getUrl();
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(apkUrl));
mActivity.startActivity(intent);
SystemClock.sleep(1500L);
System.exit(0);
}
*/
private void installAPK()
{
File apkFile =
new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), apkName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
{
Uri apkUri = FileProvider.getUriForFile(mActivity, "com.wzy.buytickets.update.fileprovider", apkFile);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else
{
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
mActivity.startActivity(intent);
}
/**
* 释放当前资源
*/
public void onDestroy()
{
if (!Constants.IS_CHECK_UPDATE && downloadManager == null) return;
downloadManager = null;
mActivity.getContentResolver().unregisterContentObserver(downloadObserver);
}
}
使用:
private UpdateManager updateManager; // 更新类
if (updateManager == null) // 初始化
{
updateManager = new UpdateManager(this);
}
updateManager.queryVersion(); // 调用(直接调用或button点击调用)