今天做了下APK版本更新的功能。其实关于APK版本更新相关的文章网上挺多的,功能实现上也并不难。基本思路就是讲当前APK的版本号和服务器上保存的最新APK包的版本号进行对比,如果当前版本小于最新版本,则进行下载更新。流程图如下:
引用的第三方jar包有okhttp,okio(为了支持okhttp)和gson:
compile 'com.squareup.okio:okio:1.5.0' compile 'com.squareup.okhttp:okhttp:2.4.0' compile 'com.google.code.gson:gson:2.3'PC端里APK版本列表的数据结构如下:
APK版本列表(APK_VERSION)
PK |
字段名称 |
字段别名 |
字段类型 |
字段长度 |
是否允许为空 |
True |
id |
标识码 |
NUMBER |
(10) |
False |
False |
apk_name |
apk名称 |
NVARCHAR2 |
(500) |
False |
False |
apk_version |
apk版本 |
NVARCHAR2 |
(100) |
False |
False |
apk_size |
apk文件大小(M) |
NVARCHAR2 |
(50) |
False |
False |
apk_path |
apk打包文件存放路径 |
NVARCHAR2 |
(2000) |
False |
False |
app_time |
apk数据记录时间 |
NVARCHAR2 |
(20) |
False |
False |
app_desc |
apk版本更新说明 |
NVARCHAR2 |
(500) |
True |
False |
remark |
备注 |
NVARCHAR2 |
(500) |
True |
对应的Android端的数据抽象类为:
public class APKVersionBean { private String apkversion; private String apkname; private String apksize; private String apkpath; private String apptime; private String apkdesr; private String remark; public String getApkversion() { return apkversion; } public void setApkversion(String apkversion) { this.apkversion = apkversion; } ... }
首先是进行版本验证功能,每个APP版本设置是在AndroidManifest文件里,如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.diit.okhttptest" android:versionCode="1" android:versionName="测试版本">versionCode就是版本号,要获取它可以采用getPackageManager的方法,代码为:
public int getVerCode(Context context){ int verCode = -1; try { verCode = context.getPackageManager().getPackageInfo("com.diit.okhttptest", 0).versionCode; } catch (PackageManager.NameNotFoundException e) { // TODO Auto-generated catch block Log.e("版本号获取异常", e.getMessage()); } return verCode; }其中com.diit.okhttptest是系统的包名。
当当前版本号小于最新版本号时候,弹出对话框,提示用户更新代码:
AlertDialog.Builder builder = new AlertDialog.Builder( activity); builder.setTitle("版本更新");//对话框标题 builder.setMessage(apkDescribe);//对话框详细内容 builder.setPositiveButton(R.string.str_button_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { _downloadAsyn(downUrl);//点击确定时候进行下载 } }); builder.setNegativeButton(R.string.str_button_cancel, null); builder.setCancelable(false); //设置为false时候点击返回键获取屏幕边缘,对话框也无法取消 builder.show(); // 显示这个消息框显示的效果为:
当点击现在更新按钮时候,进入下载的方法。在下载里首先也是弹出一个进度对话框,用来跟踪下载进度:
final ProgressDialog mProgress=new ProgressDialog(activity);//进度对话框 final Message message = updateHandler.obtainMessage(); mProgress.setIcon(R.drawable.ic_launcher_lc);//小图标 mProgress.setTitle("APK文件下载中,请稍候...");//进度对话框标题 mProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//进度对话框设置为水平进度条 mProgress.setCancelable(false); // 设置允许取消 mProgress.show();效果为:
这是进度对话框初始状态,然后可以根据下载情况进行进度赋值,代码为:
final Request request = new Request.Builder() .url(url) .build(); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(final Request request, final IOException e) { message.what = DOWNLOAD_FAIL; updateHandler.sendMessage(message); e.printStackTrace(); } @Override public void onResponse(Response response) { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; try { long total=response.body().contentLength();//获取文件大小 mProgress.setMax((int)total);//设置进度对话框总共数值大小 long sum = 0; is = response.body().byteStream(); updateFile = new File(updateDir, apkName); fos = new FileOutputStream(updateFile,false); while ((len = is.read(buf)) != -1) { sum+=len; int progress=(int)(sum*100/total); mProgress.setProgress((int)sum);//设置进度对话框当前完成数值大小 fos.write(buf, 0, len); } fos.flush(); mProgress.dismiss(); if(sum>0){ message.what = DOWNLOAD_COMPLETE; updateHandler.sendMessage(message); } }这里利用了OkHttp包进行文件下载,响应成功时候可以获取文件大小,再根据下载的进度实时更新下进度条和进度值,如图所示:
当下载成功后,进入安装界面
Uri uri = Uri.fromFile(updateFile); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); activity.startActivityForResult(installIntent,requestcode);
好了,大概功能就是这样,下面是我封装的包,代码为:
package com.diit.okhttptest; import android.app.Activity; import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.support.v7.app.AlertDialog; import android.widget.Toast; import com.squareup.okhttp.Call; import com.squareup.okhttp.Callback; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.CookieManager; import java.net.CookiePolicy; /** * Created by kaki on 2017/5/17. */ public class APKUpdateManager { private static APKUpdateManager mInstance; private final static int DOWNLOAD_COMPLETE = 0; private final static int DOWNLOAD_FAIL = 1; private final static int requestcode =100; private OkHttpClient mOkHttpClient; private String downUrl; private String apkDescribe; private String apkName; private File updateDir; private File updateFile; private Activity activity; public APKUpdateManager(APKVersionBean apkVersionBean, File updateDir, Activity activity){ this.downUrl=apkVersionBean.getApkpath(); this.apkDescribe=apkVersionBean.getApkdesr(); this.apkName=apkVersionBean.getApkname(); this.updateDir=updateDir; this.activity=activity; } public void APKUpdate(){ mOkHttpClient = new OkHttpClient(); //cookie enabled mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER)); AlertDialog.Builder builder = new AlertDialog.Builder( activity); builder.setTitle("版本更新");//对话框标题 builder.setMessage(apkDescribe);//对话框详细内容 builder.setPositiveButton(R.string.str_button_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { _downloadAsyn(downUrl);//点击确定时候进行下载 } }); builder.setNegativeButton(R.string.str_button_cancel, null); builder.setCancelable(false); //设置为false时候点击返回键获取屏幕边缘,对话框也无法取消 builder.show(); // 显示这个消息框 } private void _downloadAsyn(final String url) { final ProgressDialog mProgress=new ProgressDialog(activity);//进度对话框 final Message message = updateHandler.obtainMessage(); mProgress.setIcon(R.drawable.ic_launcher_lc);//小图标 mProgress.setTitle("APK文件下载中,请稍候...");//进度对话框标题 mProgress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//进度对话框设置为水平进度条 mProgress.setCancelable(false); // 设置允许取消 mProgress.show(); final Request request = new Request.Builder() .url(url) .build(); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(final Request request, final IOException e) { message.what = DOWNLOAD_FAIL; updateHandler.sendMessage(message); e.printStackTrace(); } @Override public void onResponse(Response response) { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; try { long total=response.body().contentLength();//获取文件大小 mProgress.setMax((int)total);//设置进度对话框总共数值大小 long sum = 0; is = response.body().byteStream(); updateFile = new File(updateDir, apkName); fos = new FileOutputStream(updateFile,false); while ((len = is.read(buf)) != -1) { sum+=len; int progress=(int)(sum*100/total); mProgress.setProgress((int)sum);//设置进度对话框当前完成数值大小 fos.write(buf, 0, len); } fos.flush(); mProgress.dismiss(); if(sum>0){ message.what = DOWNLOAD_COMPLETE; updateHandler.sendMessage(message); } } catch (IOException e) { message.what = DOWNLOAD_FAIL; updateHandler.sendMessage(message); e.printStackTrace(); } finally { try { if (is != null) { is.close(); } } catch (IOException e) { } try { if (fos != null) { fos.close(); } } catch (IOException e) { } } } }); } private Handler updateHandler = new Handler() { @SuppressWarnings("deprecation") @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLOAD_COMPLETE: Uri uri = Uri.fromFile(updateFile); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); activity.startActivityForResult(installIntent,requestcode); break; case DOWNLOAD_FAIL: Toast.makeText(activity,"APK文件下载失败,请稍候重试",Toast.LENGTH_LONG).show(); break; } } }; private String getNameFromUrl(String url) { return url.substring(url.lastIndexOf("/") + 1); } }
在Activity里调用方法为:
int newversion=Integer.parseInt(apkVersionBean.getApkversion()); int version=getVerCode(this); if(version<newversion) { APKUpdateManager apkUpdateManager = new APKUpdateManager(apkVersionBean, updateDir, this); apkUpdateManager.APKUpdate(); }
安装后的回调函数为:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode){ case requestcode: break; } }
作者:bit_kaki 发表于2017/5/17 20:48:18 原文链接
阅读:117 评论:0 查看评论