Android更新之路

现在App更新大部分都是在应用市场更新,但对于有些公司,App更新有可能还是采用古老的办法,把APK文件放入服务器,客户端通过版本号来判断软件是否更新,由于我们公司的老项目是这样处理的 ,所以记录一下该文章,把最新版的APK放入服务端,通过版本号判断客户端及时更新App
所用到的知识以及思路
1我们这里的版本号是通过xml放入服务端,客户端读取xml数据中的版本号--- 解析版本号
2客户端手机App与xml解析出来的版本号进行比较 解析的版本号大于用户正在使用的版本号 --更新
注意:有些小bug对用户体验不是很明显但为了解决这个bug也需要更新像这种更新我们这里叫做非强制更新,用户可以更新也可以不更新,对于严重的bug和功能模块的上架就需要进行强制更新,强制和非强制也是通过xml进行解析获取到---强制更新和非强制更新
3用户进行更新App需要下载APK文件包这里通过I/O流的方法进行获取APK文件
我的App是在启动页的时候进行判断更新的,也有些App是在应用程序Application中其实都差不多。
现在我们就来完成首先获取到客户端App版本号 int versionCode = context.getPackageManager().getPackageInfo(包名,0).versionCode;
创建ParseXmlService对象ParseXmlService parseXmlService = new ParseXmlService(); 保存xml数据信息HashMap mHashMap = new HashMap();
使用I/O流读取xml数据
链接网络
URL url = null
try{
url = new URL(获取服务端xml数据的API)
}catch(MalformedURLException e1){
e1.printStackTrace();
}
HttpURLConnection conn = null;
try{
conn = (HttpURLConnection).url.openConnection();
}catch(IOException e1){
e1.printStackTrace;
}
conn.setConnectTimeOut(5000);
conn.setReadTimeOut(5000);
try{
conn.connect();
}catch(IOException e2){
}
输入流获取XML文件数据
InputStream is = null;
try{
is = conn.getInputStream();
}catch(IOException e1){
e1.printStackTrace();
}
try{
mHashMap = service.parsexml(is);
}catch(Exception e){
e.printStackTrace();
}
先判断mHashMap进行非空判断
获取版本号serviceCode = Integer.valueOf(mHashMap.get("version"))
if(serviceCode >versionCode){
进行更新操作
}
进入到登陆页或者主页面
}
下面进入到第二步进行更新操作 获取xml数据中的强制更新判断的数据
String force = mHashMap.get("forceupdata")0:强制1:非强制
文件更新这里使用的是输入流和文件输出流
1首先判断手机是否存在SD卡 并且是否具有读写权限
2获得存储卡的路径设置全局成员变量mSavepath后面还需要用到
3一般情况下下载文件的API是通过XML文件解读获取到的
if(Environment.getExternalStorageState().equals(Environment,MEDIA_MOUNTED)){
String sdpath = Environment.getExternalStorageDirectory()+"/";
mSavePath = sdpath+"download";
URL url = new URL(服务器域名+XML解析出来的URL)
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestProperty("Accept-Encoding","identity");
conn.connect();
//获取文件大小
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
File file = new File(mSavePath);
//判断文件是否存在
if(file.exists()){
file.mkdir();
}
File apkFile = new File(mSavePath,mHashMap.get("appname"));
FileOutputStream fos = new FileOutputStream(apkFile);
int count = 0;
//缓存
byte buf[] = new byte[1024]
do{
int numread = is.read(buf);
count+=numread;
//计算进度条位置
progress = (int) count/length *100
//更新进度mHandler.sendEmptyMessage(DownLoad)
if(numread<=0){
//下载完成
}
}
}
然后关闭各种流操作
最后就是安装APK文件
private void installApk(){
File apkfile = new File(mSavePath,mHashMap.get("apName"));
if(!apkfile.exists()){
return
}


Intent i = new Intent(Intent.ACTION_VIEW)
i.addFlag(Intent.FLAG_ACTIVITY_NEW_TASK)
i.setDataAndType(Uri.parse("file://"+apkfile.toString()),”application/vnd.android.package-archive“);
mContext.startActivity(i);
}


最后附上完整的UpdataManager
public class UpdateManager {
private static final StringTAG ="UpdateManager";
/* 下载中*/
private static final int DOWNLOAD =1;
/* 下载结束*/
private static final int DOWNLOAD_FINISH =2;
private static final int TO_MAIN_ACTIVITY =3;
/* 保存解析的XML信息*/
HashMapmHashMap;
/* 下载保存路径*/
private StringmSavePath;
/* 记录进度条数量*/
private int progress;
/* 是否取消更新*/
private boolean cancelUpdate =false;
private ThreadnewThread;
private ContextmContext;
/* 更新进度条*/
private ProgressBarmProgress;
private DialogmDownloadDialog;
private SharePrefUtilsprefUtils;
public static int Code;
private FinalDbdb;
private StringuserId;
private Handlerhandler;
private AbHttpUtilhttpUtil =null;
private double latitude =0.0;
private double longitude =0.0;
private Activityactivity;
private ConnectivityManagermConnectivityManager;
private NetworkInfonetInfo;
@SuppressLint("HandlerLeak")
private HandlermHandler =new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
// 正在下载
case DOWNLOAD:
// 设置进度条位置
mProgress.setProgress(progress);
break;
case DOWNLOAD_FINISH:
// 安装文件
installApk();
break;
case TO_MAIN_ACTIVITY:
//mContext.startActivity(new Intent((WelcomeActivity)mContext,MainActivity.class));
break;
default:
break;
}
}
;
};
public UpdateManager(Context context) {
this.mContext = context;
activity = (Activity)mContext;
prefUtils =new SharePrefUtils(mContext);
httpUtil = AbHttpUtil.getInstance(mContext);
db = FinalDb.create(mContext);
httpUtil.setTimeout(10000);
httpUtil.setEasySSLEnabled(true);
IntentFilter mFilter =new IntentFilter();
mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
activity.registerReceiver(myNetReceiver, mFilter);
}
public void removeReceiver() {
if (null !=myNetReceiver) {
activity.unregisterReceiver(myNetReceiver);
}
}
/**
* 检测软件更新
*/
public void checkUpdate(ToTranslateActivityListener listener) {
this.listener = listener;
newThread =new Thread(new Runnable() {
@Override
public void run() {
isUpdate();
}
});
newThread.start();
handler =new Handler() {
@Override
// 当有消息发送出来的时候就执行Handler的这个方法
public void handleMessage(Message msg) {
super.handleMessage(msg);
showNoticeDialog();
}
};
}
/**
* 检查软件是否有更新版本
*
* @return
*/
private void isUpdate() {
// 获取当前软件版本
int versionCode = getVersionCode(mContext);
// 把version.xml放到网络上,然后获取文件信息
Log.d(TAG, "加载数据前6" + getSystemCurrentTime());
// 解析XML文件。 由于XML文件比较小,因此使用DOM方式进行解析
ParseXmlService service =new ParseXmlService();
URL url =null;
try {
url =new URL(Constant.HOST_URL1
+"/download/version.xml");
//+ Constant.Interface.MobiCollectAction_downloadXml);
}catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
HttpURLConnection conn =null;
try {
conn = (HttpURLConnection) url.openConnection();
}catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
try {
conn.connect();
}catch (IOException e2) {
// TODO Auto-generated catch block
//Toast.makeText(mContext, "网络连接超时,请稍后重试", Toast.LENGTH_SHORT).show();
}
InputStream is =null;
try {
is = conn.getInputStream();
}catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
mHashMap = service.parseXml(is);
}catch (Exception e) {
e.printStackTrace();
}
if (null !=mHashMap) {
prefUtils.setString(SharePrefUtils.APPOINT_CARNUM,
mHashMap.get("appointcarnum"));
prefUtils.setString(SharePrefUtils.APPOINT_INFO,
mHashMap.get("appointinfo"));
prefUtils.setString(SharePrefUtils.PARKING_MONTH_INFO,
mHashMap.get("parkingmonthinfo"));
prefUtils.setString(SharePrefUtils.CHECK_MEMBER,
mHashMap.get("checkmember"));
prefUtils
.setString(SharePrefUtils.HEADIMG, mHashMap.get("headImg"));
Intent intent =new Intent();
intent.setAction("com.android.headimg");
mContext.sendBroadcast(intent);
int serviceCode = Integer.valueOf(mHashMap.get("version"));
// 版本判断
if (serviceCode > versionCode) {
Code =1;
handler.sendEmptyMessage(0);
}else {
if (listener !=null) {
listener.onTranslateListener();
}
}
//else {
//List users = db.findAll(MemberUser.class);
//if (users != null && users.size() != 0) {
//MemberUser user = users.get(0);
//if (user != null) {
//userId = user.getMemberId();
//}
//}
//if (!TextUtils.isEmpty(userId)) {
//String user_phone = users.get(0).getUsername();
//String user_pswd = users.get(0).getPassword();
//login(user_phone, user_pswd);
//} else {
//Intent intent2 = new Intent(mContext,
//LoginActivity.class);
//mContext.startActivity(intent2);
//Activity a = (Activity) mContext;
//a.finish();
//}
//}
}else {
Intent intent2 =new Intent(mContext,
LoginActivity.class);
mContext.startActivity(intent2);
Activity a = (Activity)mContext;
a.finish();
}
}
/**
* 获取软件版本号
*
* @param context
* @return
*/
private int getVersionCode(Context context) {
int versionCode =0;
try {
// 获取软件版本号,对应AndroidManifest.xml下android:versionCode
versionCode = context.getPackageManager().getPackageInfo(
"com.android.bluetown", 0).versionCode;
}catch (NameNotFoundException e) {
e.printStackTrace();
}
return versionCode;
}
/**
* 显示软件更新对话框
*/
private void showNoticeDialog() {
// 构造对话框
Builder builder =new Builder(mContext);
builder.setTitle(R.string.soft_update_title);
builder.setMessage(mHashMap.get("updateinfo"));
builder.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode,
KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() ==0) {
if (mHashMap.get("forceupdate").equals("0")) {
System.exit(0);
}else {
if (listener !=null) {
listener.onTranslateListener();
}
}
//else {
//List users = db.findAll(MemberUser.class);
//if (users != null && users.size() != 0) {
//MemberUser user = users.get(0);
//if (user != null) {
//userId = user.getMemberId();
//}
//}
//if (!TextUtils.isEmpty(userId)) {
//String user_phone = users.get(0).getUsername();
//String user_pswd = users.get(0).getPassword();
//login(user_phone, user_pswd);
//} else {
//Intent intent = new Intent(mContext,
//LoginActivity.class);
//mContext.startActivity(intent);
//Activity a = (Activity) mContext;
//a.finish();
//}
//}
}
return false;
}
});
// 更新
builder.setPositiveButton(R.string.soft_update_updatebtn,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// 显示下载对话框
showDownloadDialog();
}
});
// 稍后更新
if (!mHashMap.get("forceupdate").equals("0")) {
builder.setNegativeButton(R.string.soft_update_later,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (listener !=null) {
listener.onTranslateListener();
}
//List users = db.findAll(MemberUser.class);
//if (users != null && users.size() != 0) {
//MemberUser user = users.get(0);
//if (user != null) {
//userId = user.getMemberId();
//}
//}
//if (!TextUtils.isEmpty(userId)) {
//String user_phone = users.get(0).getUsername();
//String user_pswd = users.get(0).getPassword();
//login(user_phone, user_pswd);
//} else {
//Intent intent = new Intent(mContext,
//LoginActivity.class);
//mContext.startActivity(intent);
//Activity a = (Activity) mContext;
//a.finish();
//}
}
});
}
Dialog noticeDialog = builder.create();
noticeDialog.setCancelable(true);
//noticeDialog.setCanceledOnTouchOutside(false);
noticeDialog.show();
}
/**
* 显示软件下载对话框
*/
private void showDownloadDialog() {
// 构造软件下载对话框
Builder builder =new Builder(mContext);
builder.setTitle(R.string.soft_updating);
// 给下载对话框增加进度条
final LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.softupdate_progress, null);
mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
builder.setView(v);
builder.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode,
KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() ==0) {
if (mHashMap.get("forceupdate").equals("0")) {
System.exit(0);
}else {
dialog.dismiss();
}
}
return false;
}
});
// 取消更新
builder.setNegativeButton(R.string.soft_update_cancel,
new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
// 设置取消状态
if (mHashMap.get("forceupdate").equals("0")) {
cancelUpdate =true;
System.exit(0);
}else {
dialog.dismiss();
cancelUpdate =true;
}
}
});
mDownloadDialog = builder.create();
mDownloadDialog.show();
mDownloadDialog.setCancelable(true);
//mDownloadDialog.setCanceledOnTouchOutside(false);
// 现在文件
downloadApk();
}
/**
* 下载apk文件
*/
private void downloadApk() {
// 启动新线程下载软件
new downloadApkThread().start();
}
/**
* 下载文件线程
*
* @author coolszy
* @date 2012-4-26
* @blog http://blog.92coding.com
*/
private class downloadApkThreadextends Thread {
@Override
public void run() {
try {
// 判断SD卡是否存在,并且是否具有读写权限
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
// 获得存储卡的路径
String sdpath = Environment.getExternalStorageDirectory()
+"/";
mSavePath = sdpath +"download";
URL url =new URL(Constant.HOST_URL1 +mHashMap.get("url"));
// 创建连接
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestProperty("Accept-Encoding", "identity");
conn.connect();
// 获取文件大小
int length = conn.getContentLength();
// 创建输入流
InputStream is = conn.getInputStream();
File file =new File(mSavePath);
// 判断文件目录是否存在
if (!file.exists()) {
file.mkdir();
}
File apkFile =new File(mSavePath, mHashMap.get("appName"));
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(DOWNLOAD);
if (numread <=0) {
// 下载完成
mHandler.sendEmptyMessage(DOWNLOAD_FINISH);
break;
}
// 写入文件
fos.write(buf, 0, numread);
}while (!cancelUpdate); // 点击取消就停止下载.
fos.close();
is.close();
}
}catch (MalformedURLException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
// 取消下载对话框显示
mDownloadDialog.dismiss();
}
}
;
/**
* 安装APK文件
*/
private void installApk() {
File apkfile =new File(mSavePath, mHashMap.get("appName"));
if (!apkfile.exists()) {
return;
}
// 通过Intent安装APK文件
Intent i =new Intent(Intent.ACTION_VIEW);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.parse("file://" + apkfile.toString()),
"application/vnd.android.package-archive");
mContext.startActivity(i);
}
private BroadcastReceivermyNetReceiver =new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
mConnectivityManager = (ConnectivityManager)activity.getSystemService(Context.CONNECTIVITY_SERVICE);
netInfo =mConnectivityManager.getActiveNetworkInfo();
if (netInfo !=null &&netInfo.isAvailable()) {
}else {
// 网络断开
List users =db.findAll(MemberUser.class);
if (users !=null && users.size() !=0) {
MemberUser user = users.get(0);
if (user !=null) {
userId = user.getMemberId();
}
}
if ("1".equals(prefUtils.getString(
SharePrefUtils.CHECKSTATE, ""))) {
TipDialog.showDialogStartNewActivity(
activity, R.string.tip,
R.string.confirm, R.string.net_no,
MainActivity.class);
}else {
if ("3".equals(prefUtils.getString(
SharePrefUtils.CHECKSTATE, ""))) {
prefUtils.setBoolean(SharePrefUtils.IS_AUTHEN_TO_AUTHING,false);
TipDialog.showDialogStartNewActivity(
activity, R.string.tip,
R.string.confirm, R.string.net_no,
AuthenticationIngActivity.class);
}else if ("1".equals(prefUtils.getString(
SharePrefUtils.CHECKSTATE, ""))) {
}else if ("2".equals(prefUtils.getString(
SharePrefUtils.CHECKSTATE, ""))) {
TipDialog.showDialogStartNewActivity(
activity, R.string.tip,
R.string.confirm, R.string.net_no,
AuthenticationActivity.class);
}else {
TipDialog.showDialogStartNewActivity(
activity, R.string.tip,
R.string.confirm, R.string.net_no,
LoginActivity.class);
}
}
}
}
}
};
public StringgetSystemCurrentTime() {
SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); // HH:mm:ss
//获取当前时间
Date date =new Date(System.currentTimeMillis());
return simpleDateFormat.format(date);
}
private ToTranslateActivityListenerlistener;
public interface ToTranslateActivityListener {
void onTranslateListener();
}
【Android更新之路】}

    推荐阅读