android apk 版本更新.doc
一个应用软件的诞生,必将带来的一个问题就是版本的更新问题。今天我就提供一个我个人的方法吧
1.问题分析
版本的更新问题可从两个方面进行考虑:一. 如何获取版本号,与当前版本号进行比对的问题。二. 如何下载最近版本,并安装的问题。
2.解决之道
解决一:我之前做的一个应用软件是通过 Web services 来进行数据的传输,当然版本号是数据也是通过这个来传输的。(本文主要介绍终端的功能实现)
我们在后台服务器段有一个固定网址放着我们的最新版本号(XML文件),然后我们通过网络,去获取这样版本号,并且与当前的版本号进行对比,从而得知是
否需要更新。说白了就是解析XML文件来获取版本号,本文采用了SAX解析器。
解决二:当我们发现有最新版本的时候,我们就需要通过网络,远程下载我们的android应用程序到手机中,并打开 application installer 来安装软件。下
载的时候我们使用 java.net 的 URLConnection 对象来创建连接,通过 InputStream 将下载的文件写入存储卡内缓存,下载完毕之后。通过自定义的 openFile() 方法打开文件,然后启动内置的Installer 程序,开始安装程序。安装完毕后,通过自制的delFile()方法,删除存储卡内的临时文件。。大功告成~
3.程序实现
主界面:
SAX解析版本号:
VesionXMLContentpackage com.android.Update;
import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler;
public class VesionXMLContentextends DefaultHandler {
private String Version;// 获取版本号
private String preTag;// 前一个元素名称
public String getVersion() {
return Version;
}
@Override
public void startDocument()throws SAXException {
Version=new String();
}
@Override
public void characters(char[] ch,int start,int length)
throws SAXException {
String data= new String(ch, start, length);
if ("string".equals(preTag)) {
Version= data;
}
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes)throws SAXException {
preTag= localName;
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
preTag= null;
}
}
SAXGetVersionServiceimport javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.InputSource;
public class SAXGetVersionService {
public static String readRssXml(InputSource inStream)throws Exception {
SAXParserFactory spf= SAXParserFactory.newInstance();
SAXParser saxParser= spf.newSAXParser();// 创建解析器
VesionXMLContent handler= new VesionXMLContent();
saxParser.parse(inStream, handler);
return handler.getVersion();
}
}
UpdateActivitypackage com.android.Update;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface; import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.URLUtil;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException; import java.net.URL;
import java.net.URLConnection;
import java.util.Properties;
import org.xml.sax.InputSource;
public class UpdateActivityextends Activity {
private static final String TAG= "DOWNLOADAPK";
// 就版本号
private String PastVersion;
// 新版本号
private String NowVersion;
//进度条
public ProgressDialog pBar;
//文件
private String currentFilePath= "";
//预安装软件的扩展名
private String fileEx="";
//软件名称
private String fileNa="";
//远程要下载的软件 -- 水果忍者。(自己选的)
private String strURL="
k";
// 自己后台的一个版本号的 web 服务
private String VersionUri=";;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(Menu.NONE, Menu.FIRST+ 1,5,"检测更新").setIcon(
android.R.drawable.ic_menu_upload);
menu.add(Menu.NONE,Menu.FIRST+2,4,"退出
").setIcon(android.R.drawable.ic_menu_delete);
// setIcon()方法为菜单设置图标,这里使用的是系统自带的图标,同学们留意一下,以
// android.R开头的资源是系统提供的,我们自己提供的资源是以R开头的
//downLoadFile("
gwen.apk");
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 解析Version网页,获取版本号
NowVersion =getVersionxml(VersionUri);
// 装载获取当前的版本号
load ();
//当有最新版本的时候
if(PastVersion!= null&&!PastVersion.equals(NowVersion))
{
//保存最新版本号
save();
Dialog dialog= new AlertDialog.Builder(UpdateActivity.this).setTitle("系统更新")
.setMessage("发现新版本,请更新~")// 设置内容
.setPositiveButton("确定",// 设置确定按钮
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
pBar= new ProgressDialog(UpdateActivity.this);
pBar.setTitle("正在下载");
pBar.setMessage("请稍候...");
pBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
fileEx=
strURL.substring(strURL.lastIndexOf(".")+1,strURL.length()).toLowerCase();
fileNa= strURL.substring(strURL.lastIndexOf("/")+1,strURL.lastIndexOf("."));
getFile(strURL);
}
}).setNegativeButton("取消",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
// 点击"取消"按钮之后退出程序
}
}).create();// 创建
// 显示对话框
dialog.show();
}
//当前为最新版本时
else{
Toast.makeText(this,"当前为最新版本", Toast.LENGTH_LONG).show();
}
return false;
}
`
//处理下载URL文件自定义函数
private void getFile(final String strPath)
{
pBar.show();
try{
if (strPath.equals(currentFilePath) ){
getDataSource(strPath);
}
currentFilePath= strPath;
Runnable r= new Runnable() {
public void run()
{
try{
getDataSource(strPath);
}catch (Exception e){
Log.e(TAG, e.getMessage(), e);
}
}
};
new Thread(r).start();
}catch(Exception e){
e.printStackTrace();
}
}
/*取得远程文件*/
private void getDataSource(String strPath)throws Exception
{
if (!URLUtil.isNetworkUrl(strPath)) {
Log.d("Tag","error");
}
else
{
//取得URL
URL myURL= new URL(strPath);
//建立联机
URLConnection conn= myURL.openConnection();
conn.connect();
//InputStream 下载文件
InputStream is= conn.getInputStream();
if (is== null) {
Log.d("tag","error");
throw new RuntimeException("stream is null");
}
//建立临时文件
File myTempFile= File.createTempFile(fileNa,"."+fileEx);
myTempFile.getAbsolutePath();
//将文件写入临时盘
FileOutputStream fos= new FileOutputStream(myTempFile);
byte buf[]= new byte[128];
do
{
int numread= is.read(buf);
if (numread<= 0)
{
break;
}
fos.write(buf,0, numread);
}while (true);
/*打开文件进行安装*/
openFile(myTempFile);
try {
is.close();
}catch (Exception ex) {
Log.d("Tag","error");
Log.e(TAG,"error:" + ex.getMessage(), ex);
}
}
}
// 在手机上打开文件的method
private void openFile(File f)
{
pBar.cancel();
Intent intent= new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
// 调用getMIMEType()来取得MimeType
String type= getMIMEType(f);
//设定intent的file与MimeType
intent.setDataAndType(Uri.fromFile(f),type);
startActivity(intent);
}
// 判断文件MimeType的method
private String getMIMEType(File f)
{
String type="";
String fName=f.getName();
// 取得扩展名
String end=fName.substring(fName.lastIndexOf(".")+1,fName.length()).toLowerCase();
// 按扩展名的类型决定MimeType
if(end.equals("m4a")||end.equals("mp3")||end.equals("mid")||end.equals("xmf")||end.equals("ogg")
||end.equals("wav"))
{
type= "audio";
}
else if(end.equals("3gp")||end.equals("mp4"))
{
type= "video";
}
else
if(end.equals("jpg")||end.equals("gif")||end.equals("png")||end.equals("jpeg")||end.equals("bmp"))
{
type= "image";
}
else if(end.equals("apk"))
{
// android.permission.INSTALL_PACKAGES
type= "application/vnd.android.package-archive";
}
else
{
type="*";
}
//如果无法直接打开,就跳出软件清单给使用者选择
if(end.equals("apk"))
{
}
else
{
type+= "/*";
}
return type;
}
//删除存储卡内的临时文件
private void delFile(String strFileName)
{
File myFile= new File(strFileName);
if(myFile.exists())
{
myFile.delete();
}
}
//SAX解析resourceUrl 页面的内容
public String getVersionxml(String resourceUrl)
{
String db= null;
URL url= null;
try {
url= new URL(resourceUrl);
}catch (MalformedURLException e) {
e.printStackTrace();
}
InputSource is=null;
InputStream stream= null;
try {
is= new InputSource(url.openStream());
is.setEncoding("UTF-8");
db= SAXGetVersionService.readRssXml(is);
}catch (Exception e) {
e.printStackTrace();
}
return db;
}
@Override
public void onOptionsMenuClosed(Menu menu) {
// Toast.makeText(this, "选项菜单关闭了", Toast.LENGTH_LONG).show();
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Toast.makeText(this,
// "选项菜单显示之前onPrepareOptionsMenu方法会被调用,你可以用此方法来根据打当时的情况调整菜单",
// Toast.LENGTH_LONG).show();
// 如果返回false,此方法就把用户点击menu的动作给消费了,onCreateOptionsMenu方法将不会被调用
return true;
}
//转载旧的版本号
boolean load ()
{
Properties properties= new Properties();
try
{
FileInputStream stream= this.openFileInput("Versionfile.cfg");
//读取文件内容
properties.load(stream);
}
catch (FileNotFoundException e)
{
return false;
}
catch(IOException e)
{
return false;
}
PastVersion= String.valueOf(properties.get("Version").toString());
return true;
}
//保存最新版本号
boolean save()
{
Properties properties= new Properties();
properties.put("Version", NowVersion);
try
{
FileOutputStream stream= this.openFileOutput("Versionfile.cfg",Context.MODE_WORLD_WRITEABLE);
properties.store(stream,"");
}
catch (FileNotFoundException e)
{
return false;
}
catch(IOException e)
{
return false;
}
return true;
}
}
特别注意: 此处必须要添加三个users-permission, 分别如下。
提供程序创建网络连接的权限:
提供程序拥有安装程序的权限:
提供创建与文件的权限:
这样就全部ok 了~~~特别注意: 此处必须要添加三个users-permission, 分别如下。
源码:(该代码只供学习,源码内需修改VersionUri
的web 服务地址,也可将版本识别去掉。直接下载。)