现在上线的APP大多要用到版本更新的功能,所以自己参考了有关更新代码,封装成了一个类,方便使用。该类实现加载MainActivity的时候自动检测是否是最新版本,如果不是则提示更新安装等操作。
1.权限声明
<!-- 访问网络的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2.VersionUpdate类
该类只需要传递一个参数,就是Activity本身(this代替),来实现的Dialog显示等。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new VersionUpdate(this);
}
3.用到的JAR包
xUtils-2.6.14.jar
主要实现访问服务器端,方便获取JSON数据等操作
4.主要方法
1.初始化,upload需要传递两个参数:1.访问网址 2.访问类型(有GETVERSION和GETAPK两个)
功能:访问接口地址,返回最新的APP版本信息
public VersionUpdate(Activity activity) {
this.activity = activity;
upload(url1, GETVERSION);
}
2.用到xUtils中httputils.send方法,根据访问类型来判断需要做的操作。因为不同的访问类型下,返回的JSON数据格式不同,不能按同一种方式解析。
public void upload(String url , final String type){
httputils = new HttpUtils();
httputils.send(HttpMethod.GET, url, new RequestCallBack<String>() {
@Override
public void onFailure(HttpException arg0, String arg1) {
Log.d("TAG", "访问失败!");
}
@Override
public void onSuccess(ResponseInfo<String> str) {
String index = str.result;
Bundle bundle = new Bundle();
bundle.putString("json", index);
Message msg = new Message();
msg.setData(bundle);
if(type.equals(GETVERSION)){
Log.d("TAG", "版本更新访问成功,得到版本信息!");
msg.what = 1;
handler.sendMessage(msg);
}
if(type.equals(GETAPK)){
Log.d("TAG", "获取APK地址!");
msg.what = 2;
handler.sendMessage(msg);
}
}
});
}
3.当我们获取到最新的APP版本信息时,需要知道我们当前APP的版本号,进而判断需不需要更新。
获取当前APP的版本号的代码: (就是mainfest文件中的android:versionName="1.0"
)
//获取当前应用的版本号
public String getVersion() {
try {
PackageManager manager = activity.getPackageManager();
PackageInfo info = manager.getPackageInfo(activity.getPackageName(), 0);
return info.versionName;
} catch (Exception e) {
e.printStackTrace();
return "无法获取版本号!";
}
}
4.Handler方法。
【判断版本号是否一致,当不一致时需要显示最新的版本信息,询问是否确定修改】
【当访问类型为GETAPK,会执行if(msg.what == 2)中的代码】
首先,为什么用handler方法?因为send方法中需要访问网路,所以是在新开的线程中去执行(因为在JAR包里,所以看不到),当需要对主线程中的控件等操作时,必须用handler回到主线程。但是本例中可以不用Handler方法。
其次,当执行到DIalog中的确定按钮后,将会再次去访问服务器段,但是传递的类型为GETAPK,之后会执行msg.what==2中的代码,执行下载APK的相关操作。
//处理网络访问版本更新后的操作
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
Bundle bundle = new Bundle();
bundle = msg.getData();
String json = bundle.getString("json");
if(msg.what == 1){
try {
JSONArray indexJsonArray = new JSONArray(json);
JSONObject jsonobject = indexJsonArray.getJSONObject(0);
version = jsonobject.getString("appVersion");
first = jsonobject.getString("First");
second = jsonobject.getString("Second");
third = jsonobject.getString("Third");
Log.d("TAG", version + first + second + third);
} catch (JSONException e) {
e.printStackTrace();
}
String version1 = getVersion();
Log.d("TAG",version1);
/**
if(version.equals(version1)){
Builder builder = new Builder(activity);
builder.setMessage("当前版本已经是最新版");
builder.setTitle("提示");
builder.setPositiveButton("确定", new OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
dialog.dismiss();
// 设置你的操作事项
}
});
builder.create().show();
}
*/
if (!version.equals(version1)) {
Builder builder = new Builder(activity);
if(second.length()==0){
builder.setMessage("有最新版本:"+version+",更新内容是:"+"\n"+first+";"+"\n"+"是否下载最新版本?");
}else if(third.length()==0){
builder.setMessage("有最新版本:"+version+",更新内容是:"+"\n"+first+";"+"\n"+second+";"+"\n"+"是否下载最新版本?");
}else{
builder.setMessage("有最新版本:"+version+",更新内容是:"+"\n"+first+";"+"\n"+second+";"+"\n"+third+";"+"\n"+"是否下载最新版本?");
}
builder.setTitle("提示");
builder.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
upload(url2,GETAPK);
dialog.dismiss();
}
});
builder.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
dialog.dismiss();
}
});
builder.setCancelable(false);
builder.create().show();
}
}
if(msg.what == 2){
try {
JSONObject jsonobject = new JSONObject(json);
url = jsonobject.getString("appHostApk");
Log.d("TAG", url);
} catch (JSONException e) {
e.printStackTrace();
}
downLoadApk();
}
};
};
5.下载APK
【设置ProgressDialog pd;的显示信息,有很多功能的】
// 1.下载apk
protected void downLoadApk() {
pd = new ProgressDialog(activity);//新建一个显示在activity上的进度条对话框
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setCancelable(true);
pd.setCanceledOnTouchOutside(false);
pd.setMessage("正在下载更新");
pd.setProgressNumberFormat("%1d KB/%2d KB");
pd.show();
new Thread() {
@Override
public void run() {
try {
File file = getFileFromServer(url, pd);
sleep(1000);
if (pd.isShowing()) {
installApk(file);
}
pd.dismiss(); // 结束掉进度条对话框
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
6.【下载APK文件到SD卡上】
// 3.从服务器下载APK
public File getFileFromServer(String path, ProgressDialog pd)
throws Exception {
// 如果相等的话表示当前的sdcard挂载在手机上并且是可用的
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
//连接下载地址,得到数据conn
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 60 * 1000);//5分钟的TimeOut限时
// 获取到文件的大小,设置PD显示的最大数据
pd.setMax(conn.getContentLength()/1000);
//把得到的APK文件变成输入流,存入Buffer缓存池
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
//新建APK文件
String ph = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/gyz";
File file = new File(ph + File.separator + "suibian_"+version+".apk");//本地SD卡上存储
FileOutputStream fos = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len;
int total = 0;
//下载的APK文件写入新建的APK文件
while ((len = bis.read(buffer)) != -1 && pd.isShowing()) {
fos.write(buffer, 0, len);
total += len;
// 获取当前下载量
pd.setProgress(total/1000);
}
if (!pd.isShowing()) {
file.delete();
}
fos.close();
bis.close();
is.close();
return file;
} else {
return null;
}
}
7.到目前为止,已经现在好了APK文件到SD卡上了。
现在只需要把APK安装到手机上(注意下载的APK签名和自己手机上的APK签名的一致)。
// 2.安装apk
protected void installApk(File file) {
Intent intent = new Intent();
// 执行动作
intent.setAction(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 执行的数据类型
intent.setDataAndType(Uri.fromFile(file),
"application/vnd.android.package-archive");// 编者按:此处Android应为android,否则造成安装不了
activity.startActivity(intent);
}