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

前言:
     一个软件想要长期的发展,必须经过更新这个过程。版本检测、版本提示并自动更新并安装这过程是必不可少的。近阶段刚做了一个项目,项目中也有更新这个需求,所以就记录一下,希望能帮到别人。

一、版本检测
     如果是Eclpse开发工具, 在自己的项目中的AndroidManifest.xml配置文件中,可以找到两个参数,一个是versionCode和versionName。 versionCode表示版本代码,是整型。 versionName表示版本名称,是字符串。升级的时候,可以检查 versionCode,也可以检查 versionName。我这里是使用了 versionName。因为涉及到小版本的更新和大版本更新。比较方法下面会贴出代码。
Eclipse:
     如果是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 {
   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文件如下:



    

    

    

    

 
     通过调用以下该方法即可实现文件下载:
/**
* 下载文件
* @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方法去实现文件下载,有需要的小伙伴,可以直接拿去使用。 如果有出错或者需要改进的地方,欢迎指点或者交流。














你可能感兴趣的:(Android,基础)