前言

前几天做了一个App引导升级的功能,现在来复盘一下,记录一下自己之前的想法,以及遇到的困难,怎么解决的。

因为是第一次写这个功能,所以还不是很了解具体的流程应该怎么做,我就去网上搜了一下,开始的搜索内容是Android引导升级功能,大致看了几个网上的例子,总结了一下。

  • 获取应用版本VersionCode与最新版本比较,需要更新则弹框提示更新
  • 更新下载并显示进度条,安装

流程还是简单的,下面就是代码的实现了

一、获取App内部版本类工具

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
public class APKVersionCodeUtils {
/**
* 获取当前本地apk的版本
*
* @param mContext
* @return
*/
public static int getVersionCode(Context mContext) {
int versionCode = 0;
try {
//获取软件版本号,对应AndroidManifest.xml下android:versionCode
versionCode = mContext.getPackageManager().
getPackageInfo(mContext.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return versionCode;
}

/**
* 获取版本号名称
*
* @param context 上下文
* @return
*/
public static String getVerName(Context context) {
String verName = "";
try {
verName = context.getPackageManager().
getPackageInfo(context.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return verName;
}

/**
* 获取App的名称
*
* @param context 上下文
*
* @return 名称
*/
public static String getAppName(Context context) {
PackageManager pm = context.getPackageManager();
//获取包信息
try {
PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
//获取应用 信息
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
//获取albelRes
int labelRes = applicationInfo.labelRes;
//返回App的名称
return context.getResources().getString(labelRes);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}

return null;
}

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

}

二、像服务器发送请求获取版本数据

请求返回的数据大致是这样的形式

1
2
3
4
5
6
7
8
/**
* oldversion : 2.0.5
* versions : 2.0.6
* content : 建议您尽快升级新版,以免影响您的使用体验~本次更新:1. 修复表情及输入表情后文字无法显示的问题。 2. 修复登录信息过期时提示“您的账号在其他设备登录”的错误。 3. 修复日记列表中日期显示错误的问题。
* wgtUrl : http:xxxxxxxxxx.apk
* wgt_size : 15444202
* update : true
*/

在进入app的时候就需要判断是否需要更新,如果需要更新的话updata的值就是true,并弹出更新提示框,如果不需要更新updata的值就是false,不做任何操作。

三、选择更新时的下载和进度条的显示

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
/* 开启新线程下载apk文件
*/
private void downloadAPK(String apkUrl) {
new Thread(new Runnable() {
@Override
public void run() {
try{
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
//String sdPath = Environment.getExternalStorageDirectory() + "/";
String sdPath = getExternalCacheDir()+ "/";
mSavePath = sdPath + "tzrj";

File dir = new File(mSavePath);
if (!dir.exists())
dir.mkdir();

// 下载文件
HttpURLConnection conn = (HttpURLConnection) new URL(apkUrl).openConnection();
conn.connect();
InputStream is = conn.getInputStream();
int length = conn.getContentLength();

File apkFile = new File(mSavePath, versionCode);
FileOutputStream fos = new FileOutputStream(apkFile);

int count = 0;
byte[] buffer = new byte[1024];
while (!mIsCancel){
int numread = is.read(buffer);
count += numread;
// 计算进度条的当前位置
mProgress = (int) (((float)count/length) * 100);
// 更新进度条
mUpdateProgressHandler.sendEmptyMessage(1);

// 下载完成
if (numread < 0){
//mUpdateProgressHandler.sendEmptyMessage(2);
mDownloadDialog.dismiss();
installApk(apkFile);
break;
}
fos.write(buffer, 0, numread);
}
fos.close();
is.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 接收消息
*/
private Handler mUpdateProgressHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
// 设置进度条
mProgressBar.setProgress(mProgress);
break;
case 2:
// 隐藏当前下载对话框
//mDownloadDialog.dismiss();
// 安装 APK 文件
//installAPK();
//getInstallIntent();
}
};
};
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
//安装程序
protected void installApk(File file) {

if (!file.exists()) {
Toast.makeText(this, "下载的安装包不存在", Toast.LENGTH_SHORT).show();
return;
}
//判读版本是否在7.0以上 todo 这里是7.0安装是会出现解析包的错误
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

// todo 在AndroidManifest中的android:authorities值 当前应用的包名:xxxxx.FileProvider(数据共享)
Uri apkUri = FileProvider.getUriForFile(this,
"xxxxx.fileprovider", file);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
install.setDataAndType(apkUri, "application/vnd.android.package-archive");
this.startActivity(install);

} else {
Intent install = new Intent(Intent.ACTION_VIEW);
install.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(install);
}

}

到这一步就完成了引导升级功能的全部操作,在最开始做出来的效果是提示更新之后,点击更新,在后台会下载新的.apk文件,下载完成之后会在消息栏提示下载完成,点击进入安装页面,这样的效果体验不佳,所以优化了一下,优化之后是,点击更新之后,会出现一个进度条展示下载的进度,一旦下载完成就直接进入到安装页面。

在做这个功能遇到的最大困难就是一开始对于未知事物的恐惧心里,因为没有接触过这个功能,下意识的就觉得很难,自己可能做不到,但是在理清了这个功能逻辑和实现步骤之后,按照这个逻辑和步骤一步一步走下去,就发现其实并没有自己想象的那么难。

希望自己以后不要被未知恐惧给吓到,办法总会有的,解决是一定能解决的,时间问题而已。