<p>由于Android项目开源所致,市面上出现了N多安卓软件市场。为了让我们开发的软件有更多的用户使用,我们需要向N多市场发布,软件升级后,我们也必须到安卓市场上进行更新,给我们增加了工作量。因此我们有必要给我们的Android应用增加自动更新的功能。</p><p>既然实现自动更新,我们首先必须让我们的应用知道是否存在新版本的软件,因此我们可以在自己的网站上放置配置文件,存放软件的版本信息:</p><pre class="brush:as3;toolbar:false"><update>
<version>2</version>
<name>baidu_xinwen_1.1.0</name>
<url>http://gdown.baidu.com/data/wisegame/f98d235e39e29031/baiduxinwen.apk</url>
</update></pre><p>在这里我使用的是XML文件,方便读取。由于XML文件内容比较少,因此可通过DOM方式进行文件的解析:</p><pre class="brush:as3;toolbar:false">publicclassParseXmlService
{
publicHashMap<String,String>parseXml(InputStreaminStream)throwsException
{
HashMap<String,String>hashMap=newHashMap<String,String>();
//实例化一个文档构建器工厂
DocumentBuilderFactoryfactory=DocumentBuilderFactory.newInstance();
//通过文档构建器工厂获取一个文档构建器
DocumentBuilderbuilder=factory.newDocumentBuilder();
//通过文档通过文档构建器构建一个文档实例
Documentdocument=builder.parse(inStream);
//获取XML文件根节点
Elementroot=document.getDocumentElement();
//获得所有子节点
NodeListchildNodes=root.getChildNodes();
for(intj=0;j<childNodes.getLength();j++)
{
//遍历子节点
NodechildNode=(Node)childNodes.item(j);
if(childNode.getNodeType()==Node.ELEMENT_NODE)
{
ElementchildElement=(Element)childNode;
//版本号
if("version".equals(childElement.getNodeName()))
{
hashMap.put("version",childElement.getFirstChild().getNodeValue());
}
//软件名称
elseif(("name".equals(childElement.getNodeName())))
{
hashMap.put("name",childElement.getFirstChild().getNodeValue());
}
//下载地址
elseif(("url".equals(childElement.getNodeName())))
{
hashMap.put("url",childElement.getFirstChild().getNodeValue());
}
}
}
returnhashMap;
}
}
通过parseXml()方法,我们可以获取服务器上应用的版本、文件名以及下载地址。紧接着我们就需要获取到我们手机上应用的版本信息:
/**
*获取软件版本号
*
*@paramcontext
*@return
*/
privateintgetVersionCode(Contextcontext)
{
intversionCode=0;
try
{
//获取软件版本号,
versionCode=context.getPackageManager().getPackageInfo("com.szy.update",0).versionCode;
}catch(NameNotFoundExceptione)
{
e.printStackTrace();
}
returnversionCode;
}</pre><p>通过该方法我们获取到的versionCode对应AndroidManifest.xml下android:versionCode。android:versionCode和android:versionName两个属性分别表示版本号,版本名称。versionCode是整数型,而versionName是字符串。由于versionName是给用户看的,不太容易比较大小,升级检查时,就可以检查versionCode。把获取到的手机上应用版本与服务器端的版本进行比较,应用就可以判断处是否需要更新软件。</p><p>处理流程</p><p><img src="/up_pic/201805/290943387171.jpg" title="290943387171.jpg" alt="1.jpg"/></p><p>处理代码</p><pre class="brush:as3;toolbar:false">packagecom.szy.update;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.InputStream;
importjava.net.HttpURLConnection;
importjava.net.MalformedURLException;
importjava.net.URL;
importjava.util.HashMap;
importandroid.app.AlertDialog;
importandroid.app.Dialog;
importandroid.app.AlertDialog.Builder;
importandroid.content.Context;
importandroid.content.DialogInterface;
importandroid.content.Intent;
importandroid.content.DialogInterface.OnClickListener;
importandroid.content.pm.PackageManager.NameNotFoundException;
importandroid.net.Uri;
importandroid.os.Environment;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.widget.ProgressBar;
importandroid.widget.Toast;
/**
*@authorcoolszy
*@date2012-4-26
*@bloghttp://blog.92coding.com
*/
publicclassUpdateManager
{
/*下载中*/
privatestaticfinalintDOWNLOAD=1;
/*下载结束*/
privatestaticfinalintDOWNLOAD_FINISH=2;
/*保存解析的XML信息*/
HashMap<String,String>mHashMap;
/*下载保存路径*/
privateStringmSavePath;
/*记录进度条数量*/
privateintprogress;
/*是否取消更新*/
privatebooleancancelUpdate=false;
privateContextmContext;
/*更新进度条*/
privateProgressBarmProgress;
privateDialogmDownloadDialog;
privateHandlermHandler=newHandler()
{
publicvoidhandleMessage(Messagemsg)
{
switch(msg.what)
{
//正在下载
caseDOWNLOAD:
//设置进度条位置
mProgress.setProgress(progress);
break;
caseDOWNLOAD_FINISH:
//安装文件
installApk();
break;
default:
break;
}
};
};
publicUpdateManager(Contextcontext)
{
this.mContext=context;
}
/**
*检测软件更新
*/
publicvoidcheckUpdate()
{
if(isUpdate())
{
//显示提示对话框
showNoticeDialog();
}else
{
Toast.makeText(mContext,R.string.soft_update_no,Toast.LENGTH_LONG).show();
}
}
/**
*检查软件是否有更新版本
*
*@return
*/
privatebooleanisUpdate()
{
//获取当前软件版本
intversionCode=getVersionCode(mContext);
//把version.xml放到网络上,然后获取文件信息
InputStreaminStream=ParseXmlService.class.getClassLoader().getResourceAsStream("version.xml");
//解析XML文件。由于XML文件比较小,因此使用DOM方式进行解析
ParseXmlServiceservice=newParseXmlService();
try
{
mHashMap=service.parseXml(inStream);
}catch(Exceptione)
{
e.printStackTrace();
}
if(null!=mHashMap)
{
intserviceCode=Integer.valueOf(mHashMap.get("version"));
//版本判断
if(serviceCode>versionCode)
{
returntrue;
}
}
returnfalse;
}
/**
*获取软件版本号
*
*@paramcontext
*@return
*/
privateintgetVersionCode(Contextcontext)
{
intversionCode=0;
try
{
//获取软件版本号,对应AndroidManifest.xml下android:versionCode
versionCode=context.getPackageManager().getPackageInfo("com.szy.update",0).versionCode;
}catch(NameNotFoundExceptione)
{
e.printStackTrace();
}
returnversionCode;
}
/**
*显示软件更新对话框
*/
privatevoidshowNoticeDialog()
{
//构造对话框
AlertDialog.Builderbuilder=newBuilder(mContext);
builder.setTitle(R.string.soft_update_title);
builder.setMessage(R.string.soft_update_info);
//更新
builder.setPositiveButton(R.string.soft_update_updatebtn,newOnClickListener()
{
@Override
publicvoidonClick(DialogInterfacedialog,intwhich)
{
dialog.dismiss();
//显示下载对话框
showDownloadDialog();
}
});
//稍后更新
builder.setNegativeButton(R.string.soft_update_later,newOnClickListener()
{
@Override
publicvoidonClick(DialogInterfacedialog,intwhich)
{
dialog.dismiss();
}
});
DialognoticeDialog=builder.create();
noticeDialog.show();
}
/**
*显示软件下载对话框
*/
privatevoidshowDownloadDialog()
{
//构造软件下载对话框
AlertDialog.Builderbuilder=newBuilder(mContext);
builder.setTitle(R.string.soft_updating);
//给下载对话框增加进度条
finalLayoutInflaterinflater=LayoutInflater.from(mContext);
Viewv=inflater.inflate(R.layout.softupdate_progress,null);
mProgress=(ProgressBar)v.findViewById(R.id.update_progress);
builder.setView(v);
//取消更新
builder.setNegativeButton(R.string.soft_update_cancel,newOnClickListener()
{
@Override
publicvoidonClick(DialogInterfacedialog,intwhich)
{
dialog.dismiss();
//设置取消状态
cancelUpdate=true;
}
});
mDownloadDialog=builder.create();
mDownloadDialog.show();
//现在文件
downloadApk();
}
/**
*下载apk文件
*/
privatevoiddownloadApk()
{
//启动新线程下载软件
newdownloadApkThread().start();
}
/**
*下载文件线程
*
*@authorcoolszy
*@date2012-4-26
*@bloghttp://blog.92coding.com
*/
privateclassdownloadApkThreadextendsThread
{
@Override
publicvoidrun()
{
try
{
//判断SD卡是否存在,并且是否具有读写权限
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
//获得存储卡的路径
Stringsdpath=Environment.getExternalStorageDirectory()+"/";
mSavePath=sdpath+"download";
URLurl=newURL(mHashMap.get("url"));
//创建连接
HttpURLConnectionconn=(HttpURLConnection)url.openConnection();
conn.connect();
//获取文件大小
intlength=conn.getContentLength();
//创建输入流
InputStreamis=conn.getInputStream();
Filefile=newFile(mSavePath);
//判断文件目录是否存在
if(!file.exists())
{
file.mkdir();
}
FileapkFile=newFile(mSavePath,mHashMap.get("name"));
FileOutputStreamfos=newFileOutputStream(apkFile);
intcount=0;
//缓存
bytebuf[]=newbyte[1024];
//写入到文件中
do
{
intnumread=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(MalformedURLExceptione)
{
e.printStackTrace();
}catch(IOExceptione)
{
e.printStackTrace();
}
//取消下载对话框显示
mDownloadDialog.dismiss();
}
};
/**
*安装APK文件
*/
privatevoidinstallApk()
{
Fileapkfile=newFile(mSavePath,mHashMap.get("name"));
if(!apkfile.exists())
{
return;
}
//通过Intent安装APK文件
Intenti=newIntent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse("file://"+apkfile.toString()),"application/vnd.android.package-archive");
mContext.startActivity(i);
}
}</pre><p>效果图</p><p><img src="/up_pic/201805/290943467026.jpg" title="290943467026.jpg" alt="2.jpg"/></p><p><img src="/up_pic/201805/290944052712.jpg" title="290944052712.jpg" alt="3.jpg"/></p><p>检查模拟器SDCARD是否存在下载文件:</p><p><img src="/up_pic/201805/290943567493.jpg" title="290943567493.jpg" alt="4.jpg"/></p>