Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

时间:2021-05-18 19:54:47

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!


算下来,TomCat服务器已经写了很长一段时间了,一直说拿他来搞点事 情,也一直没做,今天刚好有空,交流群还有人请教,就寻思着把一些相关性的原理和基础操作写下来,虽然我网络这一块还是不怎么扎实,嘿嘿,还记得我们怎么搭建的服务器吗?

地址:Android服务器——TomCat服务器的搭建

我们新建一个项目TomCatVersion

这边先来说一下原理,我们做的小例子也是十分的简单,一个首页,我们用Handler实现,然后同步检测当前版本号和系统的版本号对比,如果有升级则弹出提示框提示升级,点击确定开始下载apk,同时显示进度,等下载完成之后启动新下载的APK进行安装,如果点击取消,进入主页,如果没有升级,则直接进入主页,思路应该很清晰吧!那好,我们开始!

一,准备工作

  • 1.搭建TomCat服务器

    我们没有服务器,所以使用TomCat服务器模拟,不会搭建的请看Android服务器——TomCat服务器的搭建

  • 2.新建一个IndexActivity类,并且在AndroidManifest.xml里注册并且设置为主入口

 <activity android:name="com.lgl.tomcatversion.IndexActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
  • 3.准备一张首页的图片

    可有可无,这里作为演示就去网上下载了一张

  • 4.版本更新接口

    也就是服务器的地址,我们这里也就直接自己写一段简单的json了

{
    "versionName": "2.0",
    "versionCode": 1,
    "content": "修复多项bug!",
    "url": "http://localhost:192.168.1.101/lgl/TomCatVersion.apk"
}

我们把他放在服务器里面】

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

乱码请无视,浏览器的锅

  • 5.网络权限
 <uses-permission android:name="android.permission.INTERNET"/>

二.layout_index.xml

布局就没什么内容了,一个进度,一个文本

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/index"
    android:gravity="center_horizontal">

    <TextView
        android:gravity="center"
        android:layout_alignParentBottom="true"
        android:id="@+id/tv_version"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:textColor="@android:color/white"
        android:textSize="20sp" />

    <ProgressBar
        android:layout_centerInParent="true"
        android:layout_alignParentBottom="true"
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="60dp" />

</RelativeLayout>

三.逻辑分析

1.获取版本号

首先你的首页的文本上需要获取当前应用的版本号吧

    /**
     * 获取APP版本号
     *
     * @return
     */
    private String getAppVersion() {
        try {
            //PackageManager管理器
            PackageManager pm = getPackageManager();
            //获取相关信息
            packageInfo = pm.getPackageInfo(getPackageName(), 0);
            //版本名称
            String name = packageInfo.versionName;
            //版本号
            int version = packageInfo.versionCode;

            Log.i("版本信息", "版本名称:"+name+"版本号"+version);

            return name;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //如果出现异常抛出null
        return null;
    }

我们打印出来的Log

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

我们需要的就是这个name(版本名称)

2.解析JSON

这段json还是十分的简单的,我们直接就用原生的方式解析了,本来想用Volley的,但是演示的话,希望各位自己根据需求使用


    /**
     * 解析JSON
     */
    private void getJSON() {
        // 子线程访问,耗时操作
        new Thread() {
            public void run() {
                try {
                    // JSON地址
                    HttpURLConnection conn = (HttpURLConnection) new URL(
                            //模拟器一般有一个预留IP:10.0.2.2
                            "http://192.168.1.103:8080/lgl/update.json")
                            .openConnection();
                    //请求方式GRT
                    conn.setRequestMethod("GET");
                    //连接超时
                    conn.setConnectTimeout(5000);
                    //响应超时
                    conn.setReadTimeout(3000);
                    //连接
                    conn.connect();
                    //获取请求码
                    int responseCode = conn.getResponseCode();
                    //等于200说明请求成功
                    if(responseCode == 200){
                        //拿到他的输入流
                        InputStream in = conn.getInputStream();
                        String stream = Utils.toStream(in);

                        Log.i("JSON", stream);
                    }

                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }.start();
    }

这里我们写了一个Utils来转换流

package com.lgl.tomcatversion;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 流转换Stream的工具栏
 *
 * @author LGL
 *
 */
public class Utils {

    // 对外发放
    public static String toStream(InputStream in) throws IOException {

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // 长度
        int length = 0;
        byte[] buffer = new byte[1024];
        // -1代表读完了
        while ((length = in.read(buffer)) != -1) {
            out.write(buffer, 0, length);
        }
        // 读完关闭
        in.close();
        out.close();
        // 我们把返回的数据转换成String
        return out.toString();
    }
}

这样我们就可以把Json打印出来了

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

既然获取到了,那我们就开始解析JSON吧

在Log后面继续写代码

// 解析
JSONObject jsonObject = new JSONObject(stream);
// 获取版本名
String versionName = jsonObject.getString("versionName");
// 获取版本号
int versionCode = jsonObject.getInt("versionCode");
// 获取更新内容
String content = jsonObject.getString("content");
// 获取下载地址
String url = jsonObject.getString("url");

这样我们就解析完成了

3.版本比较以及提示更新

这里我们可以根据name或者code的比较来判断是否有更新,有更新的话,弹出提示框,点确定再更新,我这里就比较Code了,先写以恶搞获取code的方法


    /**
     * 获取versionCode
     */
    private int getCode() {
        // PackageManager管理器
        PackageManager pm = getPackageManager();
        // 获取相关信息
        try {
            packageInfo = pm.getPackageInfo(getPackageName(), 0);
            // 版本号
            int version = packageInfo.versionCode;
            return version;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return 0;

    }

然后我们接着刚才解析完JSON的地方比对,我们先把服务器的JSON数据改了

{
    "versionName": "2.0",
    "versionCode": 2,
    "content": "修复多项bug!",
    "url": "http://192.168.1.103:8080/lgl/TomCatVersion.apk"
}

这样就会提示更新了,我们检修

// 版本判断
if (versionCode > getCode()) {
    // 提示更新
    msg.what = UPDATE_YES;
} else {
    // 不更新,跳转到主页
    msg.what = UPDATE_NO;
}

子线程中我们是不能弹框的,所以我们用Handler,当我们发送UPDATE_YES的时候就弹框,也就是执行我们弹框的方法


    /**
     * 升级弹框
     */
    private void showUpdateDialog() {
        updateDialog = new CustomDialog(this, 0, 0, R.layout.dialog_update,
                R.style.Theme_dialog, Gravity.CENTER, 0);
        // 更新内容
        dialog_update_content = (TextView) updateDialog
                .findViewById(R.id.dialog_update_content);
        dialog_update_content.setText(content);
        // 确定更新
        dialog_confrim = (TextView) updateDialog
                .findViewById(R.id.dialog_confrim);
        dialog_confrim.setOnClickListener(this);
        // 取消更新
        dialog_cancel = (TextView) updateDialog
                .findViewById(R.id.dialog_cancel);
        dialog_cancel.setOnClickListener(this);
        updateDialog.show();
    }

这里我用了一个自定义的Dialog’

CustomDialog

package com.lgl.tomcatversion;

import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;

public class CustomDialog extends Dialog {

    public CustomDialog(Context context, int layout, int style) {
        this(context, WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.WRAP_CONTENT, layout, style,
                Gravity.CENTER);
    }

    public CustomDialog(Context context, int width, int height, int layout,
            int style, int gravity, int anim) {
        super(context, style);

        setContentView(layout);
        // set window params
        Window window = getWindow();
        WindowManager.LayoutParams params = window.getAttributes();
        // set width,height by density and gravity
        // float density = getDensity(context);
        params.width = WindowManager.LayoutParams.MATCH_PARENT;

        params.height = WindowManager.LayoutParams.WRAP_CONTENT;

        params.gravity = gravity;
        window.setAttributes(params);
        window.setWindowAnimations(anim);
    }

    public CustomDialog(Context context, int width, int height, int layout,
            int style, int gravity) {
        this(context, width, height, layout, style, gravity,
                R.style.pop_anim_style);
    }

}

他需要用到一些资源

dialog_update.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="150dip"
    android:layout_marginEnd="20dp"
    android:layout_marginStart="20dp"
    android:background="@drawable/dialog_bg"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/dialog_notifly_bottom"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/dialog_cancel"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:singleLine="true"
            android:text="暂不更新"
            android:textSize="18sp" />

        <View
            android:layout_width="0.2dp"
            android:layout_height="match_parent"
            android:background="#AAAAAA" />

        <TextView
            android:id="@+id/dialog_confrim"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:singleLine="true"
            android:text="立即下载"
            android:textSize="18sp" />
    </LinearLayout>

    <View
        android:id="@+id/dialog_notifly_line"
        android:layout_width="match_parent"
        android:layout_height="0.2dp"
        android:layout_above="@id/dialog_notifly_bottom"
        android:background="#AAAAAA" />

    <TextView
        android:id="@+id/dialog_update_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/dialog_notifly_line"
        android:layout_below="@+id/TextView01"
        android:layout_marginBottom="10dip"
        android:layout_marginLeft="10dip"
        android:layout_marginRight="10dip"
        android:gravity="center"
        android:singleLine="true"
        android:textSize="18sp" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="20dp"
        android:gravity="center"
        android:singleLine="true"
        android:text="检测到有新版本,是否下载?"
        android:textSize="18sp" />

</RelativeLayout>

styles.xml

 <style name="pop_anim_style">
        <item name="android:windowEnterAnimation">@anim/pop_in</item>
        <item name="android:windowExitAnimation">@anim/pop_out</item>
    </style>

    <style name="Theme_dialog" parent="@android:style/Theme.Dialog">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowNoTitle">true</item>
    </style>

以及用到的动画

pop_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromXDelta="0"
        android:fromYDelta="100%"
        android:toXDelta="0"
        android:toYDelta="0" />

</set>

pop_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="@android:integer/config_shortAnimTime"
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="100%" />

</set>

接着我们再执行一下

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

我们现在再来处理一下没有更新的逻辑,没有更新的话直接跳主页面,我们写一个方法

/**
     * 跳转主页面
     */
    private void goHome() {
        startActivity(new Intent(this, MainActivity.class));
        finish();
    }

但是这样还是有个问题,他没有更新一下子就跳过去了,所以我们在发消息的时候先让线程睡一会儿

try {
    //停留三秒钟
    Thread.sleep(3000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
// 全部走完发消息
handler.sendMessage(msg);

但是这里又出现了一个新的问题,毕竟是网络问题,他是耗时的,这样的话,万一等太久了用户体验也上不去啊,所以我们这里要做一个优化

我们在开始网络请求的时间记录一个时间

// 开始访问网络的时间
long startTime = System.currentTimeMillis();

然后再网络请求结束的时候去计算时间并且计算一共用了多少时间

// 网络访问结束的时间
long endTime = System.currentTimeMillis();
// 计算网络用了多少时间
long time = endTime - startTime;
try {
    if (time < 3000) {
    // 停留三秒钟
    Thread.sleep(3000 - time);
}
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
            e.printStackTrace();
}

4.下载更新以及下载进度

涉及到下载,这里你可以使用很多的开源框架,我这里使用的是xutils

地址:https://github.com/wyouflf/xUtils

我们下载之后拷贝在libs里就可以用了,用起来也很简单,使用之前先加个权限

   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

然后开始下载

/**
     * 下载更新
     */
    private void downloadAPK() {
        tv_pro.setVisibility(View.VISIBLE);
        // 判断是否有SD卡
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            // 获取手机根目录
            String path = Environment.getExternalStorageDirectory()
                    .getAbsolutePath() + "/TomCatVersion.apk";
            HttpUtils httpUtils = new HttpUtils();
            /**
             * 1.网络地址 2.存放地址 3.回调
             */
            httpUtils.download(url, path, new RequestCallBack<File>() {

                // 下载进度
                @Override
                public void onLoading(long total, long current,
                        boolean isUploading) {
                    // TODO Auto-generated method stub
                    super.onLoading(total, current, isUploading);

                    // 显示进度
                    tv_pro.setText(100 * current / total + "%");

                }

                // 成功
                @Override
                public void onSuccess(ResponseInfo<File> responseInfo) {
                }

                // 失败
                @Override
                public void onFailure(HttpException error, String msg) {
                    Log.i("error", msg);
                }
            });
        } else {
            Toast.makeText(getApplicationContext(), "未找到SD卡", Toast.LENGTH_LONG)
                    .show();
        }

    }

这里的代码逻辑也是十分的简单的,多吧,我们来看一下效果‘

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

更新的包体积有点小,所以一下子就百分之百了,我们去SD卡更目录看一下

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

确定是下载完成了,但是下完完之后啥也没发生啊,这就要我们再次优化了

下载完之后软起动

下载完之后自动进入安装界面,这才是真正的体验,我们在onSuccess()方法中

// 跳转系统安装页面
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setDataAndType(Uri.fromFile(new File(path)),"application/vnd.android.package-archive");
startActivity(i);

我们来看看效果

Android服务器——使用TomCat实现软件的版本检测,升级,以及下载更新进度!

大致的一个逻辑思路就是这样了

完整代码

IndexActivity

package com.lgl.tomcatversion;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.TextView;
import android.widget.Toast;

import com.lidroid.xutils.HttpUtils;
import com.lidroid.xutils.exception.HttpException;
import com.lidroid.xutils.http.ResponseInfo;
import com.lidroid.xutils.http.callback.RequestCallBack;

/**
 * 首页
 *
 * @author LGL
 *
 */
public class IndexActivity extends Activity implements OnClickListener {

    // 更新
    private static final int UPDATE_YES = 1;
    // 不更新
    private static final int UPDATE_NO = 2;
    // URL错误
    private static final int URL_ERROR = 3;
    // 没有网络
    private static final int IO_ERROR = 4;
    // 数据异常
    private static final int JSON_ERROR = 5;

    private TextView tv_version;
    private PackageInfo packageInfo;

    private JSONObject jsonObject;
    private String versionName;
    private int versionCode;
    private String content;
    private String url;

    private TextView tv_pro;

    // 升级提示框
    private CustomDialog updateDialog;
    private TextView dialog_update_content;
    private TextView dialog_confrim;
    private TextView dialog_cancel;

    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case UPDATE_YES:
                showUpdateDialog();
                break;
            case UPDATE_NO:
                goHome();
                break;
            case URL_ERROR:
                Toast.makeText(getApplicationContext(), "地址错误",
                        Toast.LENGTH_LONG).show();
                goHome();
                break;
            case IO_ERROR:
                Toast.makeText(getApplicationContext(), "请检查网络",
                        Toast.LENGTH_LONG).show();
                goHome();
                break;
            case JSON_ERROR:
                Toast.makeText(getApplicationContext(), "Json解析错误",
                        Toast.LENGTH_LONG).show();
                goHome();
                break;
            // 就算你报任何错,爸比是爱你的,依然让你进主页面
            }
        }
    };
    private String path;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_index);

        initView();
        getJSON();
    }

    /**
     * 初始化控件
     *
     * @author LGL
     */
    private void initView() {

        tv_pro = (TextView) findViewById(R.id.tv_pro);

        tv_version = (TextView) findViewById(R.id.tv_version);
        // 设置版本号
        tv_version.setText("版本号:" + getAppVersion());
    }

    /**
     * 获取APP版本号
     *
     * @return
     */
    private String getAppVersion() {
        try {
            // PackageManager管理器
            PackageManager pm = getPackageManager();
            // 获取相关信息
            packageInfo = pm.getPackageInfo(getPackageName(), 0);
            // 版本名称
            String name = packageInfo.versionName;
            // 版本号
            int version = packageInfo.versionCode;

            Log.i("版本信息", "版本名称:" + name + "版本号" + version);

            return name;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        // 如果出现异常抛出
        return "无法获取";
    }

    /**
     * 解析JSON
     */
    private void getJSON() {
        // 子线程访问,耗时操作
        new Thread() {
            public void run() {

                Message msg = Message.obtain();

                // 开始访问网络的时间
                long startTime = System.currentTimeMillis();

                try {
                    // JSON地址
                    HttpURLConnection conn = (HttpURLConnection) new URL(
                    // 模拟器一般有一个预留IP:10.0.2.2
                            "http://192.168.1.103:8080/lgl/update.json")
                            .openConnection();
                    // 请求方式GRT
                    conn.setRequestMethod("GET");
                    // 连接超时
                    conn.setConnectTimeout(5000);
                    // 响应超时
                    conn.setReadTimeout(3000);
                    // 连接
                    conn.connect();
                    // 获取请求码
                    int responseCode = conn.getResponseCode();
                    // 等于200说明请求成功
                    if (responseCode == 200) {
                        // 拿到他的输入流
                        InputStream in = conn.getInputStream();
                        String stream = Utils.toStream(in);

                        Log.i("JSON", stream);
                        jsonObject = new JSONObject(stream);
                        versionName = jsonObject.getString("versionName");
                        versionCode = jsonObject.getInt("versionCode");
                        content = jsonObject.getString("content");
                        url = jsonObject.getString("url");

                        // 版本判断
                        if (versionCode > getCode()) {
                            // 提示更新
                            msg.what = UPDATE_YES;
                        } else {
                            // 不更新,跳转到主页
                            msg.what = UPDATE_NO;
                        }
                    }

                } catch (MalformedURLException e) {
                    // URL错误
                    e.printStackTrace();
                    msg.what = URL_ERROR;
                } catch (IOException e) {
                    // 没有网络
                    e.printStackTrace();
                    msg.what = IO_ERROR;
                } catch (JSONException e) {
                    // 数据错误
                    e.printStackTrace();
                    msg.what = JSON_ERROR;
                } finally {

                    // 网络访问结束的时间
                    long endTime = System.currentTimeMillis();
                    // 计算网络用了多少时间
                    long time = endTime - startTime;

                    try {
                        if (time < 3000) {
                            // 停留三秒钟
                            Thread.sleep(3000 - time);
                        }
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    // 全部走完发消息
                    handler.sendMessage(msg);
                }
            }
        }.start();
    }

    /**
     * 获取versionCode
     */
    private int getCode() {
        // PackageManager管理器
        PackageManager pm = getPackageManager();
        // 获取相关信息
        try {
            packageInfo = pm.getPackageInfo(getPackageName(), 0);
            // 版本号
            int version = packageInfo.versionCode;
            return version;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return 0;

    }

    /**
     * 升级弹框
     */
    private void showUpdateDialog() {
        updateDialog = new CustomDialog(this, 0, 0, R.layout.dialog_update,
                R.style.Theme_dialog, Gravity.CENTER, 0);
        //如果他点击其他地方,不安装,我们就直接去
        updateDialog.setOnCancelListener(new OnCancelListener() {

            @Override
            public void onCancel(DialogInterface dialog) {
                goHome();
            }
        });
        // 更新内容
        dialog_update_content = (TextView) updateDialog
                .findViewById(R.id.dialog_update_content);
        dialog_update_content.setText(content);
        // 确定更新
        dialog_confrim = (TextView) updateDialog
                .findViewById(R.id.dialog_confrim);
        dialog_confrim.setOnClickListener(this);
        // 取消更新
        dialog_cancel = (TextView) updateDialog
                .findViewById(R.id.dialog_cancel);
        dialog_cancel.setOnClickListener(this);
        updateDialog.show();
    }

    /**
     * 点击事件
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.dialog_confrim:
            updateDialog.dismiss();
            downloadAPK();

            break;
        case R.id.dialog_cancel:
            // 跳主页面
            goHome();
            break;
        }
    }

    /**
     * 跳转主页面
     */
    private void goHome() {
        startActivity(new Intent(this, MainActivity.class));
        finish();
    }

    /**
     * 下载更新
     */
    private void downloadAPK() {
        tv_pro.setVisibility(View.VISIBLE);
        // 判断是否有SD卡
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            path = Environment.getExternalStorageDirectory().getAbsolutePath()
                    + "/TomCatVersion.apk";
            HttpUtils httpUtils = new HttpUtils();
            /**
             * 1.网络地址 2.存放地址 3.回调
             */
            httpUtils.download(url, path, new RequestCallBack<File>() {

                // 下载进度
                @Override
                public void onLoading(long total, long current,
                        boolean isUploading) {
                    // TODO Auto-generated method stub
                    super.onLoading(total, current, isUploading);

                    // 显示进度
                    tv_pro.setText(100 * current / total + "%");

                }

                // 成功
                @Override
                public void onSuccess(ResponseInfo<File> responseInfo) {

                    // 跳转系统安装页面
                    Intent i = new Intent();
                    i.setAction(Intent.ACTION_VIEW);
                    i.addCategory(Intent.CATEGORY_DEFAULT);
                    i.setDataAndType(Uri.fromFile(new File(path)),
                            "application/vnd.android.package-archive");
                    startActivity(i);
                }

                // 失败
                @Override
                public void onFailure(HttpException error, String msg) {
                    Log.i("error", msg);
                }
            });
        } else {
            Toast.makeText(getApplicationContext(), "未找到SD卡", Toast.LENGTH_LONG)
                    .show();
        }

    }
}

layout_index.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/index"
    android:gravity="center_horizontal" >

    <TextView
        android:id="@+id/tv_version"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:gravity="center"
        android:textColor="@android:color/white"
        android:textSize="20sp" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:layout_marginBottom="60dp" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginTop="207dp"
        android:gravity="center"
        android:text="欢迎"
        android:textColor="#fff"
        android:textSize="50sp" />

    <TextView
        android:textColor="#220000"
        android:visibility="invisible"
        android:id="@+id/tv_pro"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/progressBar"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="95dp"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

Demo下载地址:http://download.csdn.net/detail/qq_26787115/9463814