项目尾声,做一个在线升级的功能。做出来感觉效果还不错,拆分出来一个demo分享出来,先上图:
以下只上后台文件,前台文件和资源文件,需要的请下载源码包。
首先是一个封装的UpdateManager类,如下:
package com.example.updatedemo; import com.example.updatedemo.R; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import org.json.JSONObject; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.Window; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; /* * 检验apk是否有新版本,是否升级 * * @author yuanjiang 11.29.2014 */ public class UpdateManager { /* 上下文 */ private Context mContext; /* 下载包安装路径 */ private static final String savePath = Environment.getExternalStorageDirectory()+"/Download/"; private static final int NEW_VERSION = 3; private static final int DOWN_UPDATE = 1; private static final int DOWN_OVER = 2; /* 刷新的进度条 */ private ProgressBar mProgress; /* 新版本apk的远程路径 */ private String apkUrl ; /* 保存下载的apk的名称为 */ private String saveFileName; /* 下载进度 */ private int progress; private boolean interceptFlag = false; /* * Handler静态化,防止内存泄露 */ private static class MHandler extends Handler { /* 引用外部类 */ private WeakReference<UpdateManager> updatemanager; public MHandler(UpdateManager activity) { updatemanager = new WeakReference<UpdateManager>(activity); } /* 处理线程结果 */ @Override public void handleMessage(android.os.Message msg) { UpdateManager theClass = updatemanager.get(); switch (msg.what) { //对比后有新版本 case NEW_VERSION: theClass.showUpdateDialog((JSONObject)msg.obj); break; //正在下载,更新进度条 case DOWN_UPDATE: theClass.showProgress(); break; //下载完成,进行安装 case DOWN_OVER: theClass.installApk(); } } } /* 实例化Handler */ MHandler mHandler = new MHandler(this); //构造函数 public UpdateManager(Context context) { this.mContext = context; } /* * 检查新版本 */ public void checkVersion() { android.util.Log.i("UpdateManager","checkVersion"); Runnable checkVersionRunnable = new Runnable(){ @Override public void run() { try { //远程请求服务器,获取远程服务器上的apk版本;这里我们直接模拟返回的结果 JSONObject data = new JSONObject("{" + "\"status\":1," + "\"msg\":{" + "\"versionCode\":7," + "\"versionName\":\"1.1.7\"," + "\"versionUrl\":\"http://www.baidu.com\"," + "\"versionDesc\":\"1,新增定位功能;2,修复定位功能相关BUG;3,增加针对信息推送功能\"," + "\"versionDate\":\"2013.11.48\"," + "\"versionSize\":\"1.6M\"}}"); if(data.length()>0) //有返回数据,则发送消息 { int status = data.getInt("status"); if(status==1) { JSONObject newVersionInfo = data.getJSONObject("msg"); int versionCode = newVersionInfo.getInt("versionCode"); String versionName = newVersionInfo.getString("versionName"); saveFileName = "56ol_"+versionName+".apk"; apkUrl = newVersionInfo.getString("versionUrl"); int versionCodeClient = Utils.getversionCode(mContext); if(versionCode>versionCodeClient) //服务器版本大于本机版本,则视为有新版本 { Message message = mHandler.obtainMessage(NEW_VERSION); message.obj = newVersionInfo; mHandler.sendMessage(message); } } } } catch(Exception e) { android.util.Log.i("UpdateManager",e.toString()); } } }; new Thread(checkVersionRunnable).start();; } /* 显示进度条 * 外部类进行封装以便MHandler进行内部调用 */ public void showProgress() { mProgress.setProgress(progress); } /* * 显示版本更新提示框 */ private void showUpdateDialog(JSONObject newVersionInfo){ final AlertDialog alg = new AlertDialog.Builder(mContext).create(); alg.show(); Window win = alg.getWindow(); win.setContentView(R.layout.common_dialog_update); //显示新版本内容 TextView title_update = (TextView)win.findViewById(R.id.title_update); TextView title_date = (TextView)win.findViewById(R.id.title_date); TextView title_size = (TextView)win.findViewById(R.id.title_size); TextView versionDesc1 = (TextView)win.findViewById(R.id.versionDesc1); TextView versionDesc2 = (TextView)win.findViewById(R.id.versionDesc2); TextView versionDesc3 = (TextView)win.findViewById(R.id.versionDesc3); try{ title_update.setText(newVersionInfo.getString("versionName")+"版本升级提示"); title_date.setText("发布时间:"+newVersionInfo.getString("versionDate")); title_size.setText("大小:"+newVersionInfo.getString("versionSize")); //提示内容按";"进行整合,这里拆分到数组中 String desc[] = newVersionInfo.getString("versionDesc").split(";"); versionDesc1.setText(desc[0]); versionDesc2.setText(desc[1]); versionDesc3.setText(desc[2]); Button positiveButton = (Button)win.findViewById(R.id.PositiveButton); Button negativeButton = (Button)win.findViewById(R.id.NegativeButton); positiveButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub alg.dismiss(); showDownloadDialog(); } }); negativeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub alg.dismiss(); } }); }catch(Exception e){ e.printStackTrace(); } } /* * 显示下载中界面 */ private void showDownloadDialog(){ final AlertDialog alg = new AlertDialog.Builder(mContext).create(); alg.show(); Window win = alg.getWindow(); win.setContentView(R.layout.common_dialog_progress); mProgress = (ProgressBar)win.findViewById(R.id.update_progress); Button negativeButton = (Button)win.findViewById(R.id.NegativeButton); negativeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub alg.dismiss(); interceptFlag = true; //中止下载 } }); downloadApk(); } /* * 下载apk * @param url */ private void downloadApk(){ Runnable mdownApkRunnable = new Runnable() { @Override public void run() { try { URL url = new URL(apkUrl); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.connect(); int length = conn.getContentLength(); InputStream is = conn.getInputStream(); File file = new File(savePath); File ApkFile = new File(file,saveFileName); FileOutputStream fos = new FileOutputStream(ApkFile); int count = 0; byte buf[] = new byte[1024]; do{ int numread = is.read(buf); count += numread; progress =(int)(((float)count / length) * 100); //更新进度 mHandler.sendEmptyMessage(DOWN_UPDATE); if(numread <= 0){ //下载完成通知安装 mHandler.sendEmptyMessage(DOWN_OVER); break; } fos.write(buf,0,numread); }while(!interceptFlag); //点击取消就停止下载. fos.close(); is.close(); } catch (MalformedURLException e) { android.util.Log.i("MalformedURLException",e.toString()); } catch(IOException e){ android.util.Log.i("IOException",e.toString()); } } }; new Thread(mdownApkRunnable).start(); } /* * 安装apk * @param url */ private void installApk(){ File apkfile = new File(savePath+saveFileName); if (!apkfile.exists()) { return; } Intent i = new Intent(Intent.ACTION_VIEW); i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive"); mContext.startActivity(i); } }
UpdateManager.java中有用到一个Utils.java工具类,里面有一个获取本机版本的方法,如下:
package com.example.updatedemo; import android.content.Context; public class Utils { /* * 获取当前app的versionCode * return int */ public static int getversionCode(Context context) { int verCode = -1; try { verCode = context.getPackageManager().getPackageInfo("com.com56ol.main", 0).versionCode; } catch (Exception e) { android.util.Log.e("mUtils-gerversionCode", e.getMessage()); } return verCode; } }
然后就是实例化UpdateManger执行升级了,就两行代码,如下:
package com.example.updatedemo; import com.example.updatedemo.UpdateManager; import android.os.Bundle; import android.app.Activity; /** * 在线升级demo * * @author yuanjiang 11.27.2013 */ public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //检测版本是否需要更新 UpdateManager mUpdateManager = new UpdateManager(this); mUpdateManager.checkVersion(); } }
资源下载地址:http://download.csdn.net/detail/eclothy/8222061
关于更新安装apk后,不能打开“完成、打开”的界面,而是直接返回桌面,需要修改UpdateManager.java中的installApk()方法,为实例化的intent增加intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),如下:
/* * 安装apk * @param url */ private void installApk(){ File apkfile = new File(savePath+saveFileName); if (!apkfile.exists()) { return; } Intent i = new Intent(Intent.ACTION_VIEW); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //设置flag,开启新任务 i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive"); mContext.startActivity(i); }