步骤:
1.检测当前版本的信息AndroidManifest.xml–>manifest–>[Android]
2.从服务器获取版本号(版本号存在于xml文件中)并与当前检测到的版本进行匹配,如果不匹配,提示用户进行升级,如果匹配则进入程序主界面。(demo中假设需要更新)
3.当提示用户进行版本升级时,如果用户点击了“更新”,系统将自动从服务器上下载安装包并进行自动升级,如果点击取消将进入程序主界面。
效果图如下:
下面介绍一下代码的实现:
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