摘要
版本更新这一块涉及的知识点比较少,但也花了一天时间,仅做记录用,为了方便大家理解,我画了一张流程图。需求比较简单,以后可以根据产品需求适当更改。
以下版本更新工具类
/**
* Created by minmin.shen
* on 2019/1/23
* 检查更新版本工具类
*/
public class UpdateManager {
private String downLoadPath = "";
private String url = "";//apk下载地址
private boolean isforce = false;
private String oldApkName = "";
private String newApkName = "";
private Context context;
private BaseDialog updataDialog;
private BaseDialog installDialog;
private ProgressDialog progressDialog;
private FragmentManager fm;
public static UpdateManager updateManager;
public static UpdateManager getInstance() {
if (updateManager == null) {
updateManager = new UpdateManager();
}
return updateManager;
}
public void start(){
if(checkIsHaveNewAPK()){
showInstallDialog("发现新版本,是否安装?");
}else{
showUpdataDialog();
}
}
/**
* 版本更新提示框
*/
public void showUpdataDialog() {
updataDialog = BaseDialog.getInstance().setTitle("提示").setContent("发现新版本,是否更新?")
.setPositionText("取消", new View.OnClickListener() {
@Override
public void onClick(View v) {
updataDialog.dismiss();
if (isforce) {
System.exit(0);
}
}
})
.setNegativeText("更新", new View.OnClickListener() {
@Override
public void onClick(View v) {
updataDialog.dismiss();
createProgress(context);
new Thread(new Runnable() {
@Override
public void run() {
downloadApk();
}
}).start();
}
});
updataDialog.show(fm, "dialog for update");
}
/**
* 弹出安装Dialog
*/
private void showInstallDialog(String content){
installDialog = BaseDialog.getInstance().setTitle("提示").setContent(content)
.setPositionText("取消", new View.OnClickListener() {
@Override
public void onClick(View v) {
installDialog.dismiss();
if (isforce) {
System.exit(0);
}
}
})
.setNegativeText("安装", new View.OnClickListener() {
@Override
public void onClick(View v) {
installDialog.dismiss();
File fileAPK = new File(downLoadPath, newApkName);
installApk(context, fileAPK);
}
});
installDialog.show(fm, "dialog for install");
}
/**
* 检查有没有最新的APK
*/
private boolean checkIsHaveNewAPK(){
File file = new File(downLoadPath);
if (!file.exists()) {
file.mkdirs();
}
File fileAPK = new File(downLoadPath, newApkName);
if(fileAPK.exists()){
return true;
}
return false;
}
/**
* 删除旧的apk
*/
private void delOldApk(){
File fileAPK = new File(downLoadPath, oldApkName);
if(fileAPK.exists()){
fileAPK.delete();
}
}
/**
* 下载APK
*/
private void downloadApk() {
try {
final long startTime = System.currentTimeMillis();
Log.i("DOWNLOAD", "startTime=" + startTime);
//获取文件名
URL myURL = new URL(url);
URLConnection conn = myURL.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
int fileSize = conn.getContentLength();//根据响应获取文件大小
Log.i("DOWNLOAD", "总大小="+fileSize);
if (fileSize <= 0) throw new RuntimeException("无法获知文件大小 ");
if (is == null) throw new RuntimeException("stream is null");
File file1 = new File(downLoadPath);
if (!file1.exists()) {
file1.mkdirs();
}
//把数据存入路径+文件名
FileOutputStream fos = new FileOutputStream(downLoadPath + "/" + newApkName);
byte buf[] = new byte[1024];
int downLoadFileSize = 0;
do {
//循环读取
int numread = is.read(buf);
if (numread == -1) {
break;
}
fos.write(buf, 0, numread);
downLoadFileSize += numread;
Log.i("DOWNLOAD", "downLoadFileSize="+downLoadFileSize);
Log.i("DOWNLOAD", "fileSize="+fileSize);
Log.i("DOWNLOAD", "download downLoadFileSize="+(int)((float)downLoadFileSize*100/fileSize));
progressDialog.setProgress((int)((float)downLoadFileSize*100/fileSize));
//更新进度条
} while (true);
delOldApk();
progressDialog.dismiss();
showInstallDialog("下载完成,是否安装?");
Log.i("DOWNLOAD", "download success");
Log.i("DOWNLOAD", "totalTime=" + (System.currentTimeMillis() - startTime));
is.close();
} catch (Exception ex) {
Log.e("DOWNLOAD", "error: " + ex.getMessage(), ex);
}
}
/**
* 强制更新时显示在屏幕的进度条
*/
private void createProgress(Context context) {
progressDialog = new ProgressDialog(context);
progressDialog.setMax(100);
progressDialog.setCancelable(false);
progressDialog.setMessage("正在下载...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.show();
}
/**
* 安装apk
*/
private void installApk(Context context, File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
//判断是否是AndroidN以及更高的版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri contentUri = FileProvider.getUriForFile(context, "com.baozun.book.fileProvider", file);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
context.startActivity(intent);
}
/**
* apk网络地址
*/
public UpdateManager setContext(Context context) {
this.context = context;
return this;
}
/**
* apk网络地址
*/
public UpdateManager setUrl(String url) {
this.url = url;
return this;
}
/**
* 新版本文件名
*/
public UpdateManager setNewFileName(String fileName) {
this.newApkName = fileName;
return this;
}
/**
* 旧版本文件名
*/
public UpdateManager setOldFileName(String fileName) {
this.oldApkName = fileName;
return this;
}
/**
* Fragment管理器
*/
public UpdateManager setFragmentManager(FragmentManager fm) {
this.fm = fm;
return this;
}
/**
* 下载路径
*/
public UpdateManager setDownloadPath(String downLoadPath) {
this.downLoadPath = downLoadPath;
return this;
}
/**
* 是否强制更新
*/
public UpdateManager setIsforce(boolean isforce) {
this.isforce = isforce;
return this;
}
}
下面是发起调用
public static void checkUpdate(Context context, android.support.v4.app.FragmentManager fm, float versionCode, String url, boolean isForced) {
if (versionCode > Float.parseFloat(Util.getCurrentVersionName(context))) {
String downLoadPath = context.getExternalFilesDir(null).toString() + "/download/";
String newFileName = "U_Reading"+versionCode+".apk";
String oldFileName = "U_Reading"+Float.parseFloat(Util.getCurrentVersionName(context))+".apk";
//设置参数
UpdateManager.getInstance()
.setContext(context)
.setFragmentManager(fm)
.setDownloadPath(downLoadPath)
.setNewFileName(newFileName)
.setOldFileName(oldFileName)
.setUrl(url)
.setIsforce(isForced)
.start();
}
}
其中安装apk需要注意下,在manifest文件中加入代码
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.baozun.book.fileProvider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
在资源文件中加入
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="files_root"
path="Android/data/com.baozun.book/" />
<external-path
name="external_storage_root"
path="." />
</paths>
先简单写一下,待详细整理
---------------------------------------------------------------2019/4/16号更新----------------------------------------------------------------
近期发现代码安装APK的时候,在华为手机上不会弹出安装界面
需要在清单文件中配置权限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />