Android应用更新之自动检测版本及自动升级

步骤:

1.检测当前版本的信息AndroidManifest.xml�C>manifest�C>[Android]

2.从服务器获取版本号(版本号存在于xml文件中)并与当前检测到的版本进行匹配,如果不匹配,提示用户进行升级,如果匹配则进入程序主界面。(demo中假设需要更新)

3.当提示用户进行版本升级时,如果用户点击了“更新”,系统将自动从服务器上下载安装包并进行自动升级,如果点击取消将进入程序主界面。

效果图如下:

Android应用更新之自动检测版本及自动升级_第1张图片
Android应用更新之自动检测版本及自动升级_第2张图片

Android应用更新之自动检测版本及自动升级_第3张图片

Android应用更新之自动检测版本及自动升级_第4张图片

下面介绍一下代码的实现:

1.获取应用的当前版本号,我是封装了一个工具类来获取

 // 获取本版本号,是否更新
  int vision = Tools.getVersion(this);

获取当前版本号工具类:

public class Tools {
 /**
  * 检查是否存在SDCard
  *
  * @return
  */
 public static boolean hasSdcard() {
  String state = Environment.getExternalStorageState();
  if (state.equals(Environment.MEDIA_MOUNTED)) {
   return true;
  } else {
   return false;
  }
 }

 /**
  * 2 * 获取版本号 3 * @return 当前应用的版本号 4
  */
 public static int getVersion(Context context) {
  try {
   PackageManager manager = context.getPackageManager();
   PackageInfo info = manager.getPackageInfo(context.getPackageName(),
     0);
   String version = info.versionName;
   int versioncode = info.versionCode;
   return versioncode;
  } catch (Exception e) {
   e.printStackTrace();
  }
  return 0;
 }

}

2.获取服务器版本号,是否要更新(此处就是简单的网络请求拿到需要的数据即可,我是写了固定值)

 // 获取更新版本号
 private void getVersion(final int vision) {
//   {"data":{"content":"其他bug修复。","id":"2","api_key":"android",
//   // "version":"2.1"},"msg":"获取成功","status":1}
  String data = "";
  //网络请求获取当前版本号和下载链接
  //实际操作是从服务器获取
  //demo写死了

  String newversion = "2.1";//更新新的版本号
  String content = "\n" +
    "就不告诉你我们更新了什么-。-\n" +
    "\n" +
    "----------万能的分割线-----------\n" +
    "\n" +
    "(ㄒoㄒ) 被老板打了一顿,还是来告诉你吧:\n" +

    "1.下架商品误买了?恩。。。我搞了点小动作就不会出现了\n" +
    "2.侧边栏、弹框优化 ―― 这个你自己去探索吧,总得留点悬念嘛-。-\n";//更新内容
  String url = "http://openbox.mobilem.360.cn/index/d/sid/3429345";//安装包下载地址

  double newversioncode = Double
    .parseDouble(newversion);
  int cc = (int) (newversioncode);

  System.out.println(newversion + "v" + vision + ",,"
    + cc);
  if (cc != vision) {
   if (vision < cc) {
    System.out.println(newversion + "v"
      + vision);
    // 版本号不同
    ShowDialog(vision, newversion, content, url);
   }
  }
 }

3.接下来就是下载文件了

(1) 显示下载
此处用的是自定义按钮:

 /**
  * 升级系统
  *
  * @param content
  * @param url
  */
 private void ShowDialog(int vision, String newversion, String content,
       final String url) {
  final MaterialDialog dialog = new MaterialDialog(this);
  dialog.content(content).btnText("取消", "更新").title("版本更新 ")
    .titleTextSize(15f).show();
  dialog.setCanceledOnTouchOutside(false);
  dialog.setOnBtnClickL(new OnBtnClickL() {// left btn click listener
   @Override
   public void onBtnClick() {
    dialog.dismiss();
   }
  }, new OnBtnClickL() {// right btn click listener

   @Override
   public void onBtnClick() {
    dialog.dismiss();
    // pBar = new ProgressDialog(MainActivity.this,
    // R.style.dialog);
    pBar = new CommonProgressDialog(MainActivity.this);
    pBar.setCanceledOnTouchOutside(false);
    pBar.setTitle("正在下载");
    pBar.setCustomTitle(LayoutInflater.from(
      MainActivity.this).inflate(
      R.layout.title_dialog, null));
    pBar.setMessage("正在下载");
    pBar.setIndeterminate(true);
    pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    pBar.setCancelable(true);
    // downFile(URLData.DOWNLOAD_URL);
    final DownloadTask downloadTask = new DownloadTask(
      MainActivity.this);
    downloadTask.execute(url);
    pBar.setOnCancelListener(new DialogInterface.OnCancelListener() {
     @Override
     public void onCancel(DialogInterface dialog) {
      downloadTask.cancel(true);
     }
    });
   }
  });
 }

原生的按钮:

 new android.app.AlertDialog.Builder(this)
    .setTitle("版本更新")
    .setMessage(content)
    .setPositiveButton("更新", new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
      pBar = new CommonProgressDialog(MainActivity.this);
      pBar.setCanceledOnTouchOutside(false);
      pBar.setTitle("正在下载");
      pBar.setCustomTitle(LayoutInflater.from(
        MainActivity.this).inflate(
        R.layout.title_dialog, null));
      pBar.setMessage("正在下载");
      pBar.setIndeterminate(true);
      pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      pBar.setCancelable(true);
      // downFile(URLData.DOWNLOAD_URL);
      final DownloadTask downloadTask = new DownloadTask(
        MainActivity.this);
      downloadTask.execute(url);
      pBar.setOnCancelListener(new DialogInterface.OnCancelListener() {
       @Override
       public void onCancel(DialogInterface dialog) {
        downloadTask.cancel(true);
       }
      });
     }
    })
    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
     @Override
     public void onClick(DialogInterface dialog, int which) {
      dialog.dismiss();
     }
    })
    .show();

(2)通过异步任务实现进度++

 /**
  * 下载应用
  *
  * @author Administrator
  */
 class DownloadTask extends AsyncTask {

  private Context context;
  private PowerManager.WakeLock mWakeLock;

  public DownloadTask(Context context) {
   this.context = context;
  }

  @Override
  protected String doInBackground(String... sUrl) {
   InputStream input = null;
   OutputStream output = null;
   HttpURLConnection connection = null;
   File file = null;
   try {
    URL url = new URL(sUrl[0]);
    connection = (HttpURLConnection) url.openConnection();
    connection.connect();
    // expect HTTP 200 OK, so we don't mistakenly save error
    // report
    // instead of the file
    if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
     return "Server returned HTTP "
       + connection.getResponseCode() + " "
       + connection.getResponseMessage();
    }
    // this will be useful to display download percentage
    // might be -1: server did not report the length
    int fileLength = connection.getContentLength();
    if (Environment.getExternalStorageState().equals(
      Environment.MEDIA_MOUNTED)) {
     file = new File(Environment.getExternalStorageDirectory(),
       DOWNLOAD_NAME);

     if (!file.exists()) {
      // 判断父文件夹是否存在
      if (!file.getParentFile().exists()) {
       file.getParentFile().mkdirs();
      }
     }

    } else {
     Toast.makeText(MainActivity.this, "sd卡未挂载",
       Toast.LENGTH_LONG).show();
    }
    input = connection.getInputStream();
    output = new FileOutputStream(file);
    byte data[] = new byte[4096];
    long total = 0;
    int count;
    while ((count = input.read(data)) != -1) {
     // allow canceling with back button
     if (isCancelled()) {
      input.close();
      return null;
     }
     total += count;
     // publishing the progress....
     if (fileLength > 0) // only if total length is known
      publishProgress((int) (total * 100 / fileLength));
     output.write(data, 0, count);

    }
   } catch (Exception e) {
    System.out.println(e.toString());
    return e.toString();

   } finally {
    try {
     if (output != null)
      output.close();
     if (input != null)
      input.close();
    } catch (IOException ignored) {
    }
    if (connection != null)
     connection.disconnect();
   }
   return null;
  }

  @Override
  protected void onPreExecute() {
   super.onPreExecute();
   // take CPU lock to prevent CPU from going off if the user
   // presses the power button during download
   PowerManager pm = (PowerManager) context
     .getSystemService(Context.POWER_SERVICE);
   mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
     getClass().getName());
   mWakeLock.acquire();
   pBar.show();
  }

  @Override
  protected void onProgressUpdate(Integer... progress) {
   super.onProgressUpdate(progress);
   // if we get here, length is known, now set indeterminate to false
   pBar.setIndeterminate(false);
   pBar.setMax(100);
   pBar.setProgress(progress[0]);
  }

  @Override
  protected void onPostExecute(String result) {
   mWakeLock.release();
   pBar.dismiss();
   if (result != null) {

//    // 申请多个权限。大神的界面
//    AndPermission.with(MainActivity.this)
//      .requestCode(REQUEST_CODE_PERMISSION_OTHER)
//      .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
//      // rationale作用是:用户拒绝一次权限,再次申请时先征求用户同意,再打开授权对话框,避免用户勾选不再提示。
//      .rationale(new RationaleListener() {
//          @Override
//          public void showRequestPermissionRationale(int requestCode, Rationale rationale) {
//           // 这里的对话框可以自定义,只要调用rationale.resume()就可以继续申请。
//           AndPermission.rationaleDialog(MainActivity.this, rationale).show();
//          }
//         }
//      )
//      .send();
    // 申请多个权限。
    AndPermission.with(MainActivity.this)
      .requestCode(REQUEST_CODE_PERMISSION_SD)
      .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
      // rationale作用是:用户拒绝一次权限,再次申请时先征求用户同意,再打开授权对话框,避免用户勾选不再提示。
      .rationale(rationaleListener
      )
      .send();


    Toast.makeText(context, "您未打开SD卡权限" + result, Toast.LENGTH_LONG).show();
   } else {
    // Toast.makeText(context, "File downloaded",
    // Toast.LENGTH_SHORT)
    // .show();
    update();
   }

  }
 }

此处下载apk文件,需要获取SD的读写权限(用的是严大的权限库)

权限库GitHub

private static final int REQUEST_CODE_PERMISSION_SD = 101;

 private static final int REQUEST_CODE_SETTING = 300;
 private RationaleListener rationaleListener = new RationaleListener() {
  @Override
  public void showRequestPermissionRationale(int requestCode, final Rationale rationale) {
   // 这里使用自定义对话框,如果不想自定义,用AndPermission默认对话框:
   // AndPermission.rationaleDialog(Context, Rationale).show();

   // 自定义对话框。
   AlertDialog.build(MainActivity.this)
     .setTitle(R.string.title_dialog)
     .setMessage(R.string.message_permission_rationale)
     .setPositiveButton(R.string.btn_dialog_yes_permission, new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
       dialog.cancel();
       rationale.resume();
      }
     })

     .setNegativeButton(R.string.btn_dialog_no_permission, new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
       dialog.cancel();
       rationale.cancel();
      }
     })
     .show();
  }
 };
 //----------------------------------SD权限----------------------------------//


 @PermissionYes(REQUEST_CODE_PERMISSION_SD)
 private void getMultiYes(List grantedPermissions) {
  Toast.makeText(this, R.string.message_post_succeed, Toast.LENGTH_SHORT).show();
 }

 @PermissionNo(REQUEST_CODE_PERMISSION_SD)
 private void getMultiNo(List deniedPermissions) {
  Toast.makeText(this, R.string.message_post_failed, Toast.LENGTH_SHORT).show();

  // 用户否勾选了不再提示并且拒绝了权限,那么提示用户到设置中授权。
  if (AndPermission.hasAlwaysDeniedPermission(this, deniedPermissions)) {
   AndPermission.defaultSettingDialog(this, REQUEST_CODE_SETTING)
     .setTitle(R.string.title_dialog)
     .setMessage(R.string.message_permission_failed)
     .setPositiveButton(R.string.btn_dialog_yes_permission)
     .setNegativeButton(R.string.btn_dialog_no_permission, null)
     .show();

   // 更多自定dialog,请看上面。
  }
 }

 //----------------------------------权限回调处理----------------------------------//

 @Override
 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
   grantResults) {
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  /**
   * 转给AndPermission分析结果。
   *
   * @param object  要接受结果的Activity、Fragment。
   * @param requestCode 请求码。
   * @param permissions 权限数组,一个或者多个。
   * @param grantResults 请求结果。
   */
  AndPermission.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  switch (requestCode) {
   case REQUEST_CODE_SETTING: {
    Toast.makeText(this, R.string.message_setting_back, Toast.LENGTH_LONG).show();
    //设置成功,再次请求更新
    getVersion(Tools.getVersion(MainActivity.this));
    break;
   }
  }
 }

(3) 当apk文件下载完毕时,打开安装

private void update() {
  //安装应用
  Intent intent = new Intent(Intent.ACTION_VIEW);
  intent.setDataAndType(Uri.fromFile(new File(Environment
      .getExternalStorageDirectory(), DOWNLOAD_NAME)),
    "application/vnd.android.package-archive");
  startActivity(intent);
 }

源码

此demo已经上传到GitHub,如有需要自行下载

GitHub: 链接地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

你可能感兴趣的:(Android应用更新之自动检测版本及自动升级)