Android 版本检测、文件下载并更新

来源:互联网 发布:数据库安全管理办法 编辑:程序博客网 时间:2024/06/01 08:18
前言:
     一个软件想要长期的发展,必须经过更新这个过程。版本检测、版本提示并自动更新并安装这过程是必不可少的。近阶段刚做了一个项目,项目中也有更新这个需求,所以就记录一下,希望能帮到别人。

一、版本检测
     如果是Eclpse开发工具,在自己的项目中的AndroidManifest.xml配置文件中,可以找到两个参数,一个是versionCode和versionName。versionCode表示版本代码,是整型。versionName表示版本名称,是字符串。升级的时候,可以检查versionCode,也可以检查versionName。我这里是使用了versionName。因为涉及到小版本的更新和大版本更新。比较方法下面会贴出代码。
Eclipse:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.hjy.demo"    android:versionCode="1"    android:versionName="1.0.0" >
     如果是AS的开发工具,那么versionCode和versionName是在app文件下的build.gradle
文件中。
Android studio:
defaultConfig {    applicationId "com.smarthx.projectassistant"    minSdkVersion 14    targetSdkVersion 23    versionCode 1    versionName "1.0.0"}
     通过上面配置代码版本以及名称,接下来就有一个问题,就是如何在java代码中获取这些参数呢?
/** * 获取当前包名信息 * 这些信息是从相对应的Androdimanifest.xml * @param context * @return */private static PackageInfo getPackageInfo(Context context) {    PackageInfo pi = null;    try {        PackageManager pm = context.getPackageManager();        pi = pm.getPackageInfo(context.getPackageName(),                PackageManager.GET_CONFIGURATIONS);        return pi;    } catch (Exception e) {        e.printStackTrace();    }    return pi;}/*** 版本名* @param context* @return*/public static String getVersionName(Context context) {    return getPackageInfo(context).versionName;}/*** 版本号* @param context* @return*/public static int getVersionCode(Context context) {    return getPackageInfo(context).versionCode;}
     通过这些方法可以获取到版本代码以及版本名称,通过服务器(java写的)拉取数据,匹配服务器的版本和当前APP的版本是否是一致的(比如:服务器versionName 是1.0.1,本地versionName是1.0.0),不一致做更新动作。versionName匹配代码如下:
/*** 比较版本号的大小,前者大则返回一个正数,后者大返回一个负数,相等则返回0* @param version1* @param version2* @return*/public static int compareVersion(String version1, String version2) throws Exception {     if (version1 == null || version2 == null) {          throw new Exception();     }     String[] versionArray1 = version1.split("\\.");//注意此处为正则匹配,不能用.;     String[] versionArray2 = version2.split("\\.");     int idx = 0;     int minLength = Math.min(versionArray1.length, versionArray2.length);//取最小长度值     int diff = 0;     while (idx < minLength          && (diff = versionArray1[idx].length() - versionArray2[idx].length()) == 0          && (diff = versionArray1[idx].compareTo(versionArray2[idx])) == 0)     {          //再比较字符          ++idx;     }     //如果已经分出大小,则直接返回,如果未分出大小,则再比较位数,有子版本的为大;     diff = (diff != 0) ? diff : versionArray1.length - versionArray2.length;     return diff;}
     上面compareVersion方法可以根据返回值去执行动作,如果输入参数version2是当前APP版本名称,version1是远程服务器版本名称,输出返回值为正数时,那么就要做更新动作,输出返回值为负数或者为0时,那么就不做任何动作。至于更新的动作,就是向服务器发起一个请求,该请求就是下载最新版本的apk,然后安装并取代旧版本。

二、文件下载
     这里的下载使用AsyncTask(android提供的轻量级的异步类)做下载动作。这里为了开发方便,将一些公共的函数,单独放在UpgradeTask类中实现,代码如下:
/*** 下载文件工具类* @author hjy* created at 2016/12/9 15:14*/public class UpgradeTask extends AsyncTask<String, Integer, String> {   private static final int TIME_OUT = 25000;   Context context;   private static final int NOTIFY_ID = 12345;   private NotificationManager mNotifyMgr;   private RemoteViews views;   private Notification nofity;   private VersionInfo verInfo;   private String APK_FILE_NAME ;   private int fileLen;   public UpgradeTask(Context context,String APK_FILE_NAME,int fileLen){      this.context =context;      this.APK_FILE_NAME =APK_FILE_NAME;      this.fileLen = fileLen;   }   @Override   protected void onPreExecute() {      showNotify();   }   protected String doInBackground(String... params) {      //Log.d("test","开始下载···");      InputStream is = null;      FileOutputStream fos = null;      try {         URL url = new URL(params[0]);         HttpURLConnection conn = (HttpURLConnection) url               .openConnection();         // conn.getContentLength()// 注意,虚拟地址不能使用这个方法获得文件大小         // 为http请求设置超时时间         conn.setConnectTimeout(TIME_OUT);         conn.setReadTimeout(TIME_OUT);         if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {//          ToastUtils.showToast(context, "服务端正在维护");//          Toast.makeText(context, "服务端正在维护", Toast.LENGTH_SHORT).show();            return null;         }         is = conn.getInputStream();         // conn.getContentLength()         File upgradeApk = new File(APK_FILE_NAME);         if (!upgradeApk.exists()) {            upgradeApk.getParentFile().mkdirs();         }         fos = new FileOutputStream(upgradeApk);         byte[] buffer = new byte[1024];         int loadedLen = 0;         int len = 0;         int count = 0;         while (-1 != (len = is.read(buffer))) {            fos.write(buffer, 0, len);            loadedLen += len;            int perc = loadedLen * 100 / fileLen;            // 每1%更新一次            if (perc > 1 * count){               count++;               publishProgress(loadedLen);            }         }         fos.flush();      } catch (SocketTimeoutException e) {         // 处理超时事件      } catch (MalformedURLException e) {      } catch (IOException e) {      } finally {         if (is != null) {            try {               is.close();            } catch (IOException e) {            }         }         if (fos != null) {            try {               fos.close();            } catch (IOException e) {            }         }      }      //Log.d("test","开始完成···");      return null;   }   @Override   protected void onProgressUpdate(Integer... values) {      updateNotify(values[0]);   }   protected void onPostExecute(String result) {      // 提示安装apk//    ToastUtils.showToast(context, "下载完成,请点击通知安装");      Toast.makeText(context, "下载完成,请点击通知安装", Toast.LENGTH_SHORT).show();      Intent intent = new Intent(Intent.ACTION_VIEW);      intent.setDataAndType(Uri.fromFile(new File(APK_FILE_NAME)),            "application/vnd.android.package-archive");      context.startActivity(intent);      finishNotify();      //SPUtils.writeIsUpgrade(MyApp.context, false);   }   /**    * 通知栏初始化    * @author hjy    * created at 2016/12/8 11:38    */   private void showNotify() {      mNotifyMgr = (NotificationManager) context.getSystemService(            Context.NOTIFICATION_SERVICE);      Intent intent = new Intent();      PendingIntent contentIntent = PendingIntent.getActivity(context,            0, intent, 0);      views = new RemoteViews(context.getPackageName(), R.layout.custom_notify);      views.setTextViewText(R.id.textView1, "准备下载");      views.setTextViewText(R.id.textView2, "");      views.setProgressBar(R.id.progressBar1, 10, 0, false);      nofity = new NotificationCompat.Builder(context)            .setSmallIcon(R.mipmap.icon_shanchu_focused)            .setTicker("开始更新...")            .setWhen(System.currentTimeMillis())            // .setContentTitle("contentTitle")            // .setContentText("contentText")            .setAutoCancel(true).setContent(views)            .setContentIntent(contentIntent).build();      mNotifyMgr.notify(NOTIFY_ID, nofity);   }   /**    * 更新中    * @author hjy    * created at 2016/12/8 11:38    */   private void updateNotify(int currLen) {      views.setTextViewText(R.id.textView1, currLen * 100 / fileLen            + "%");      views.setProgressBar(R.id.progressBar1, fileLen, currLen,            false);      mNotifyMgr.notify(NOTIFY_ID, nofity);   }   /**    * 更新完毕    * @author hjy    * created at 2016/12/8 11:37    */   private void finishNotify() {      Intent intent = new Intent(Intent.ACTION_VIEW);      intent.setDataAndType(Uri.fromFile(new File(APK_FILE_NAME)),            "application/vnd.android.package-archive");      PendingIntent contentIntent = PendingIntent.getActivity(context,            0, intent, 0);      nofity.contentIntent = contentIntent;      views.setTextViewText(R.id.textView1, "下载完成,点击更新");      views.setImageViewResource(R.id.imageView1,R.mipmap.ic_launcher);      views.setViewVisibility(R.id.progressBar1, View.INVISIBLE);      mNotifyMgr.notify(NOTIFY_ID, nofity);   }   public void setVersionInfo(VersionInfo verInfo) {      this.verInfo = verInfo;   }}
     通知栏的布局文件custom_notify.xml文件如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/RelativeLayout1"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:padding="8dp"    android:orientation="vertical"    android:background="#FFFFFF" >    <ImageView        android:id="@+id/imageView1"        android:layout_width="40dp"        android:layout_height="40dp"        android:layout_marginRight="12dp"        android:scaleType="fitXY"        android:layout_alignParentLeft="true"        android:layout_alignParentTop="true"        android:src="@mipmap/ic_launcher" />    <TextView        android:id="@+id/textView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentTop="true"        android:layout_toRightOf="@+id/imageView1"        android:text="Medium Text"        android:textColor="@color/mainStyle"        android:textAppearance="?android:attr/textAppearanceMedium" />    <TextView        android:id="@+id/textView2"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBottom="@+id/imageView1"        android:layout_alignLeft="@+id/textView1"        android:textColor="#000000"        android:text="TextView" />    <ProgressBar        android:id="@+id/progressBar1"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBottom="@+id/textView2"        android:layout_alignParentRight="true"        android:layout_toRightOf="@+id/textView2" /></RelativeLayout> 
     通过调用以下该方法即可实现文件下载:
/*** 下载文件* @author hjy* @param updateUrl  APP下载地址* @param appPath    APP下载缓存路径* @param fileLength 文件总大小(progress总长度)* created at 2016/12/8 14:37*/private void loadFile(String updateUrl,String appPath,int fileLength){    UpgradeTask task = new UpgradeTask(LoginActivity.this, appPath, fileLength);    task.execute(updateUrl);}
    通过以上UpgradeTask工具类调用execute方法去实现文件下载,有需要的小伙伴,可以直接拿去使用。如果有出错或者需要改进的地方,欢迎指点或者交流。














0 0
原创粉丝点击