上一篇配置好服务器后,就可以进行客户端的实现了。
客户端的实现包括三个过程,版本号的检测和比较,安装包文件的下载,安装包文件的安装。
版本号的检测,需要下载version.xml文件,然后解析判断是否安装。
文件下载代码:
try {
URL url = new URL("http://192.168.21.243/version.xml");
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(5*1000);
conn.setRequestMethod("GET");
conn.connect();
InputStream verstream = conn.getInputStream();
ParseXmlService service = new ParseXmlService();
hashMap = service.parseXml(verstream);
Log.v(TAG, "version:"+hashMap.get("version"));
Log.v(TAG, "name:"+hashMap.get("name"));
Log.v(TAG, "url:"+hashMap.get("url"));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
使用ParseXmlService类进行解析,解析代码如下:
public class ParseXmlService {
String TAG = "ParseXmlService";
public HashMap<String, String> parseXml(InputStream inStream) throws Exception{
HashMap<String, String> hashMap = new HashMap<String, String>();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(inStream, "UTF-8");
int eventType = parser.getEventType();
while(eventType != XmlPullParser.END_DOCUMENT)
{
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
break;
case XmlPullParser.START_TAG:
if (parser.getName().equals("version")) {
eventType = parser.next();
hashMap.put("version", parser.getText());
}else if (parser.getName().equals("name")) {
eventType = parser.next();
hashMap.put("name", parser.getText());
}else if (parser.getName().equals("url")) {
eventType = parser.next();
hashMap.put("url", parser.getText());
}
break;
case XmlPullParser.END_TAG:
break;
}
eventType = parser.next();
}
return hashMap;
}
}
解析完以后,如果版本号比当前的版本号要高,就触发下载与更新。
下载apk的程序:
void dowloadApk(){
//String savepath = getApplicationContext().getFilesDir().getPath()+"/data/user/";
//String savepath = "/data/user/";
Log.v(TAG,"into the dowloadApk");
String upgradefile = "http://192.168.21.243/upgrade.apk";
URL url = null;
try {
url = new URL(upgradefile);
} catch (MalformedURLException e1) {
e1.printStackTrace();
}
try {
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.connect();
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
// File file = new File(savepath);
// if (!file.exists())
// {
// file.mkdir();
// }
//File apkFile = new File("/mnt/nand/", "upgrade.apk");
//FileOutputStream fos = new FileOutputStream(apkFile);
//FileOutputStream fos = getApplicationContext().openFileOutput("upgrade.apk",Context.MODE_PRIVATE);
FileOutputStream fos = getApplicationContext().openFileOutput("upgrade.apk",Context.MODE_WORLD_READABLE);
int count = 0;
byte buf[] = new byte[256];
int numread = 0;
do{
numread = is.read(buf,0,256);
count += numread;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.v(TAG,"dowloading the data numread:"+numread);
progress = (int) (((float) count / length) * 100);
mHandler.sendEmptyMessage(DOWNLOAD);
if(numread >= 0){
fos.write(buf, 0, numread);
}
if (numread <= 0)
{
break;
}
}while(!cancelUpdate);
fos.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
mDownloadDialog.dismiss();
if(!cancelUpdate){
mHandler.sendEmptyMessage(FINISH_DIALOG);
}
if(cancelUpdate)
cancelUpdate = false;
Log.v(TAG,"out the dowloadApk");
}
其中注意的是下载apk需要另开一个线程实现,同时记得加上网络和存储介质的访问权限
private class downloadApkThread extends Thread{
@Override
public void run()
{
dowloadApk();
//showDownloadDialog();
}
}
new downloadApkThread().start();
在AndroidManifest.xml中加入相应的权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
下载完之后,会在/data/data/yingyong/files/下生成相应的文件,宏
Context.MODE_WORLD_READABLE
很关键,否则安装的时候没有权限会报错。
安装实现的相应的代码:
public void ApkInstall(){
//Intent intent = new Intent(this,InstallActivity.class);
//startActivity(intent);
String apkpath = getApplicationContext().getFilesDir().getPath() + "/upgrade.apk";
Uri uri = Uri.fromFile(new File(apkpath));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
}
在代码中,
Intent.FLAG_ACTIVITY_NEW_TASK
这个参数很重要,否则在程序安装到一半时就会出现闪退的现象,其实这种安装不属于静默安装,而是通过使用每个客户端设备使用的默认安装程序来安装。Google这种架构的设计主要是出于安全的方面考虑,试想一下,如果使用静默安装,用户根本不知道程序都获取了哪些权限,这就给用户带来了不可控的风险。
总结,在这个过程中并没有设计到UI的设计,这个设计可以放到下一节去讲,主要是涉及到进度条的操作,
安卓自带的进度条实在是太丑了。
在代码设计时,任何的UI操作都不要在下载线程中实现,最好使用消息机制发送消息,在主线程中实现。