Android版本更新 借鉴: Android版本更新知识(检测、升级)总结
先说遇到的问题,7.0,8.0及以上版本采用旧方法更新,首先无法安装,添加响应权限之后,更新包安装之后,点击打开图标,应用无反应,点击图标打开正常。
解决方案:
1.版本更新的策略:比对 versionCode 如服务器versionCode>本地安装包
则弹出升级提示框,进行应用下载。
添加网络权限,在application标签下添加 provider,指定: android:resource="@xml/filepaths"
mainest
...
res xml文件夹下添加:filepaths.xml
2.代码如下:
SplashActivity中
获取权限 verifyStoragePermissions(this);//
versionName= ApkUtil.packageName(mContext);
versionCode= ApkUtil.packageCode(mContext);
mHttpUtil.getMobileAppInfo(new ProgressSubscriber(mContext,true) {
@Override
public void next(VersionModel model) {
String code=model.getCode();
if(code.equals(Constant.SUCCESS)){
VersionModel.AppInfo app=model.getAppInfo();
int resultVersionCode=Integer.parseInt(app.getVersionCode());
String resultVersionName=app.getVersionName();
Log.d("MyInfo","resultVersionCode=="+resultVersionCode+",versionCode="+versionCode);
Log.d("MyInfo","resultVersionName=="+resultVersionName+",versionName="+versionName);
if(resultVersionCode>versionCode){//服务器版本大于本地版本
showUpdateDialog(model,app);
}else{//跳转到登录页面
Message msg=handler.obtainMessage();
handler.sendMessage(msg);
}
}else{//跳转到登录页面
Message msg=handler.obtainMessage();
handler.sendMessage(msg);
}
}
},0);
动态申明权限:
//动态获取内存存储权限
public static void verifyStoragePermissions(Activity activity) {
/**
* 动态获取权限,Android 6.0 新特性,一些保护权限,除了要在AndroidManifest中声明权限,还要使用如下代码动态获取
*/
if (Build.VERSION.SDK_INT >= 23) {
int REQUEST_CODE_CONTACT = 101;
String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
//验证是否许可权限
for (String str : permissions) {
if (activity.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
//申请权限
activity.requestPermissions(permissions, REQUEST_CODE_CONTACT);
return;
}
}
}
}
3.更新提示框:
/**
* 弹出提示更新的dialog
*/
private void showUpdateDialog(final VersionModel model,final VersionModel.AppInfo app) {
final int forceUpdate=app.getForceUpdate();
String remark=app.getRemark();
UpdateDialog updateDialog=new UpdateDialog(mContext,R.style.progress_dialog);
updateDialog.setOnPositiveListener(new OnPositiveListener() {
@Override
public void onPositive() {
//从服务器端下载最新apk
downloadApk(model);
}
});
updateDialog.setOnNegativeListener(new OnNegativeListener() {
@Override
public void onNegative() {
if(forceUpdate==1){//跳转到登录页面
System.exit(0);
}else{//返回
Message msg=handler.obtainMessage();
handler.sendMessage(msg);
}
}
});
updateDialog.show();
}
4.下载应用:(进度条显示 多少M)
关键代码
dialog.setProgressNumberFormat("%1d Mb /%2d Mb");//这里设置的是进度条下面显示的文件大小和下载了多
/**
* 从服务器端下载最新apk
*/
private void downloadApk(VersionModel model) {
//显示下载进度
ProgressDialog dialog = new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
dialog.setTitle("版本更新");
dialog.setMessage("正在下载中,请稍候...");
dialog.setProgressNumberFormat("%1d Mb /%2d Mb");//这里设置的是进度条下面显示的文件大小和下载了多
dialog.show();
String url=model.getPreUrl()+model.getAppInfo().getApkUri();
Log.d("MyInfo","updateApkUrl=="+url);
//访问网络下载apk
new Thread(new DownloadApk(dialog,url)).start();
}
5.开启线程下载应用
/**
* 访问网络下载apk
*/
private class DownloadApk implements Runnable {
private ProgressDialog dialog;
private String url;
InputStream is;
FileOutputStream fos;
public DownloadApk(ProgressDialog dialog,String url) {
this.dialog = dialog;
this.url=url;
}
@Override
public void run() {
Log.d("MyInfo","url=="+url);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().get().url(url).build();
try {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
Log.d("MyInfo", "开始下载apk------");
//获取内容总长度
long contentLength = response.body().contentLength();
//设置最大值
// dialog.setMax((int) contentLength);
dialog.setMax((int)contentLength/1024/1024);
//保存到sd卡
File apkFile = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".apk");
fos = new FileOutputStream(apkFile);
//获得输入流
is = response.body().byteStream();
//定义缓冲区大小
byte[] bys = new byte[1024];
int progress = 0;
int len = -1;
while ((len = is.read(bys)) != -1) {
try {
Thread.sleep(1);
fos.write(bys, 0, len);
fos.flush();
progress += len;
//设置进度
// dialog.setProgress(progress);
dialog.setProgress(progress/1024/1024);
} catch (InterruptedException e) {
Message msg = handler.obtainMessage();
msg.what = SHOW_ERROR;
msg.obj = "ERROR:10002";
handler.sendMessage(msg);
}
}
Log.d("MyInfo", "下载apk完成------");
//下载完成,提示用户安装
autoInstallApk(mContext,apkFile);
}
} catch (IOException e) {
Log.d("MyInfo","error=="+e.getMessage());
Message msg = handler.obtainMessage();
msg.what = SHOW_ERROR;
msg.obj = "ERROR:10003";
handler.sendMessage(msg);
} finally {
//关闭io流
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
is = null;
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
fos = null;
}
}
dialog.dismiss();
}
}
6.应用安装,此处代码与之前的写法略有不同,(适配7.0 8.0的方案)
private void autoInstallApk(Context context, File file) {
//Intent intent = new Intent(Intent.ACTION_VIEW)//以前的写法,替换为下面的
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {// 小于7.0
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
} else {
//以下语句不添加,下载之后点击打开无反应
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
// 声明需要的临时的权限
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// 第二个参数,即第一步中配置的authorities
Uri contentUri = FileProvider.getUriForFile(SplashActivity.this, BuildConfig.APPLICATION_ID + ".fileprovider", file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
}
context.startActivity(intent);
}