服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android应用更新之自动检测版本及自动升级

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

2022-07-31 12:07流水潺媛 Android

这篇文章主要为大家详细介绍了Android应用更新之自动检测版本及自动升级,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

步骤:

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

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

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

效果图如下:

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

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

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

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

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

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

获取当前版本号工具类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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.获取服务器版本号,是否要更新(此处就是简单的网络请求拿到需要的数据即可,我是写了固定值)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 获取更新版本号
 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) 显示下载
此处用的是自定义按钮:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
 * 升级系统
 *
 * @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);
    }
   });
  }
 });
}

原生的按钮:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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)通过异步任务实现进度++

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/**
  * 下载应用
  *
  * @author Administrator
  */
 class DownloadTask extends AsyncTask<String, Integer, String> {
 
  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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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<String> grantedPermissions) {
  Toast.makeText(this, R.string.message_post_succeed, Toast.LENGTH_SHORT).show();
 }
 
 @PermissionNo(REQUEST_CODE_PERMISSION_SD)
 private void getMultiNo(List<String> 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文件下载完毕时,打开安装

?
1
2
3
4
5
6
7
8
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: 链接地址

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

原文链接:https://blog.csdn.net/Imshuyuan/article/details/62886741

延伸 · 阅读

精彩推荐