2、更新提示

来源:互联网 发布:养哈士奇 知乎 编辑:程序博客网 时间:2024/06/06 21:38

在进入splash界面的时候后台启动线程,联网检查是否有更新版本可用,如果没有新版本则splash界面显示后进入主界面,否则显示升级对话框让用户选择是否进行更新。

1、权限设置

因为需要联网,所以AndroidManifest.xml文件需要添加访问网络的权限:

<uses-permission android:name="android.permission.INTERNET" />
本人就是由于忘记添加该权限,在后面的运行中出现错误:

12-23 03:24:26.999    1528-1541/com.example.mobilesafe W/System.err﹕ java.net.SocketException: socket failed: EACCES (Permission denied)12-23 03:24:26.999    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.socket(IoBridge.java:576)12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at java.net.PlainSocketImpl.create(PlainSocketImpl.java:201)12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at java.net.Socket.checkOpenAndCreate(Socket.java:664)12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at java.net.Socket.connect(Socket.java:808)12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.Platform.connectSocket(Platform.java:131)12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.Connection.connect(Connection.java:101)12-23 03:24:27.009    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)12-23 03:24:27.019    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)12-23 03:24:27.019    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:503)12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.SplashActivity$checkUpdate.run(SplashActivity.java:146)12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ at java.lang.Thread.run(Thread.java:841)12-23 03:24:27.029    1528-1541/com.example.mobilesafe W/System.err﹕ Caused by: libcore.io.ErrnoException: socket failed: EACCES (Permission denied)12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.Posix.socket(Native Method)12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.BlockGuardOs.socket(BlockGuardOs.java:181)12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.socket(IoBridge.java:561)12-23 03:24:27.079    1528-1541/com.example.mobilesafe W/System.err﹕ ... 13 more

2、服务器更新配置

这里使用wampserver搭建本地服务器,更新配置文件放在X:\wamp\www\app\mobilesafe目录下,配置内容为:

<?xml version="1.0" encoding="utf-8"?><info>    <ver>2.0</ver>    <desc>亲,有新版本了,赶紧更新吧!</desc>    <apkurl>http://10.0.2.2/app/mobilesafe/mobilesafe.apk</apkurl> </info>


3、设置服务器地址

因为服务器地址属于常量字符串,这里添加到strings.xml中:

<?xml version="1.0" encoding="utf-8"?><resources>    <string name="app_name">mobilesafe</string>    <string name="serverurl">http://10.0.2.2/app/mobilesafe/update.xml</string></resources>

这里是使用本机进行测试的,注意Android访问本机的IP地址是:10.0.2.2,如果使用127.0.0.1会出现如下错误:

12-23 03:29:15.189    1573-1586/com.example.mobilesafe W/System.err﹕ java.net.ConnectException: failed to connect to /127.0.0.1 (port 80) after 5000ms: isConnected failed: ECONNREFUSED (Connection refused)12-23 03:29:15.189    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.isConnected(IoBridge.java:223)12-23 03:29:15.189    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.connectErrno(IoBridge.java:161)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.connect(IoBridge.java:112)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.net.Socket.connect(Socket.java:843)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.Platform.connectSocket(Platform.java:131)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.Connection.connect(Connection.java:101)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:296)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:503)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.SplashActivity$checkUpdate.run(SplashActivity.java:146)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at java.lang.Thread.run(Thread.java:841)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ Caused by: libcore.io.ErrnoException: isConnected failed: ECONNREFUSED (Connection refused)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ at libcore.io.IoBridge.isConnected(IoBridge.java:208)12-23 03:29:15.199    1573-1586/com.example.mobilesafe W/System.err﹕ ... 15 more

相关参考:http://www.myexception.cn/operating-system/754403.html


4、更新信息结构体

按照服务器更新配置,更新信息共有三个字段:版本号,更新提示文本,apk下载地址:

package com.example.mobilesafe;/** * Created by sing on 13-12-23. */public class UpdateInfo {    //服务器端版本号    private String version;    //服务器端升级提示    private String desc;    //服务器端apk下载地址    private String apkurl;    public String getVersion() {        return version;    }    public void setVersion(String version) {        this.version = version;    }    public String getDesc() {        return desc;    }    public void setDesc(String desc) {        this.desc = desc;    }    public String getApkurl() {        return apkurl;    }    public void setApkurl(String apkurl) {        this.apkurl = apkurl;    }}

5、XML更新配置解析类

注意XmlPullParser解析XML的nextText存在bug:

12-23 03:46:07.439    1729-1748/com.example.mobilesafe W/System.err﹕ org.xmlpull.v1.XmlPullParserException: END_TAG expected (position:START_TAG <version>@3:14 in java.io.InputStreamReader@b2ef2718)12-23 03:46:07.449    1729-1748/com.example.mobilesafe W/System.err﹕ at org.kxml2.io.KXmlParser.nextText(KXmlParser.java:2077)12-23 03:46:07.479    1729-1748/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.UpdateInfoParser.getUpdateInfo(UpdateInfoParser.java:33)12-23 03:46:07.479    1729-1748/com.example.mobilesafe W/System.err﹕ at com.example.mobilesafe.SplashActivity$checkUpdate.run(SplashActivity.java:153)12-23 03:46:07.499    1729-1748/com.example.mobilesafe W/System.err﹕ at java.lang.Thread.run(Thread.java:841)

参考解决:http://blog.csdn.net/nxh_love/article/details/7109762,

这里使用的方法是:当前的位置不是END_TAG时,在调用nextText()之后再调用nextTag(),完整代码:

package com.example.mobilesafe;import android.util.Xml;import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;import java.io.IOException;import java.io.InputStream;/** * Created by sing on 13-12-23. */public class UpdateInfoParser {    /**     *解析一个utf-8格式的xml输入流,返回一个UpdateInfo对象     * XmlPullParser解析bug参考解决:http://blog.csdn.net/nxh_love/article/details/7109762     * @param is     * @return UpdateInfo对象     * @throws XmlPullParserException     * @throws IOException     */    public static UpdateInfo getUpdateInfo(InputStream is) throws XmlPullParserException, IOException {        UpdateInfo info = new UpdateInfo();        //获取一个pull解析的实例        XmlPullParser parser = Xml.newPullParser();        //解析xml        parser.setInput(is, "UTF-8");        parser.nextTag();        int type = parser.getEventType();        while (parser.nextTag() == XmlPullParser.START_TAG) {            String tag = parser.getName();            String text = parser.nextText();            if (parser.getEventType() != XmlPullParser.END_TAG) {                parser.nextTag();            }            if (tag.equals("ver")) {                info.setVersion(text);            } else if (tag.equals("desc")) {                info.setDesc(text);            } else if (tag.equals("apkurl")) {                info.setApkurl(text);            }        }        return info;    }}

6、SplashActivity::OnCreate创建检查更新的线程

        //检查更新        new Thread(new checkUpdate()) {        }.start();


    /**     * 检查更新     */    private class checkUpdate implements Runnable {       public void run() {           long startTime = System.currentTimeMillis();           long endTime = startTime;           Message msg = Message.obtain();           try {               //获取服务器更新地址               String serverurl = getResources().getString(R.string.serverurl);               URL url = new URL(serverurl);               HttpURLConnection conn = (HttpURLConnection)url.openConnection();               conn.setRequestMethod("GET");               conn.setConnectTimeout(5000);               int code = conn.getResponseCode();               if (code == 200) {                   //success                   InputStream is = conn.getInputStream();                    //解析出更新信息                   updateinfo = UpdateInfoParser.getUpdateInfo(is);                   endTime = System.currentTimeMillis();                   long time = endTime - startTime;                   if (time < 2000) {                       try {                           Thread.sleep(2000 - time);                       } catch (InterruptedException e) {                           e.printStackTrace();                       }                   }                   msg.what = GET_INFO_SUCCESS;                   handler.sendMessage(msg);               } else {                   //服务器错误                   msg.what = SERVER_ERROR;                   handler.sendMessage(msg);                   endTime = System.currentTimeMillis();                   long time = endTime - startTime;                   if (time < 2000) {                       try {                           Thread.sleep(2000 - time);                       } catch (InterruptedException e) {                           e.printStackTrace();                       }                   }               }           } catch (MalformedURLException e) {               msg.what = SERVER_URL_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (ProtocolException e) {               msg.what = PROTOCOL_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (IOException e) {               msg.what = IO_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (XmlPullParserException e) {               msg.what = XML_PARSER_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (Exception e) {               msg.what = UNKNOWN_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           }       }    }


7、添加消息处理函数,在界面中统一显示

   /**     * 消息处理器     */    private Handler handler = new Handler() {         public void handleMessage(Message msg) {            switch (msg.what) {                case GET_INFO_SUCCESS:                    String serverVersion = updateinfo.getVersion();                    String currentVersion = getVersion();                    if (currentVersion.equals(serverVersion)) {                        Log.i(TAG, "版本号相同无需升级,直接进入主界面");                    }else {                        Log.i(TAG, "版本号不同需升级,显示升级对话框");                        showUpdateDialog();                    }                    break;                case SERVER_ERROR:                    Toast.makeText(getApplicationContext(), "服务器内部异常", 1).show();                    break;                case SERVER_URL_ERROR:                    Toast.makeText(getApplicationContext(), "服务器路径错误", 1).show();                    break;                case PROTOCOL_ERROR:                    Toast.makeText(getApplicationContext(), "协议错误", 1).show();                    break;                case XML_PARSER_ERROR:                    Toast.makeText(getApplicationContext(), "XML解析错误", 1).show();                    break;                case IO_ERROR:                    Toast.makeText(getApplicationContext(), "I/O错误", 1).show();                    break;                case UNKNOWN_ERROR:                    Toast.makeText(getApplicationContext(), "未知错误", 1).show();                    break;            }        }    };

8、当本地版本号与服务器端获取的版本号不同时提示升级对话框

/**     * 显示升级提示对话框     */    protected void showUpdateDialog() {        //创建对话框构造器        AlertDialog.Builder builder = new AlertDialog.Builder(this);        //设置对话框图标        builder.setIcon(getResources().getDrawable(R.drawable.notification));        //设置对话框标题        builder.setTitle("升级提示");        //设置更新信息为对话框提示内容        builder.setMessage(updateinfo.getDesc());        //设置升级按钮及响应事件        builder.setPositiveButton("升级", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialog, int which) {            }        });        //设置取消按钮及响应事件        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialog, int which) {            }        });        //创建并显示对话框        builder.create().show();    }

9、SplashActivity完整代码

package com.example.mobilesafe;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.Bundle;import android.os.Message;import android.util.Log;import android.view.Window;import android.view.WindowManager;import android.view.animation.AlphaAnimation;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.Toast;import org.xmlpull.v1.XmlPullParserException;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.MalformedURLException;import java.net.ProtocolException;import java.net.URL;import android.os.Handler;public class SplashActivity extends Activity {    //常量定义    public static final int UNKNOWN_ERROR = 99;    public static final int GET_INFO_SUCCESS = 100;    public static final int SERVER_ERROR = 101;    public static final int SERVER_URL_ERROR = 102;    public static final int PROTOCOL_ERROR = 103;    public static final int IO_ERROR = 104;    public static final int XML_PARSER_ERROR = 105;    public static final String TAG = "SplashActivity";    //获取的服务器端的更新信息    UpdateInfo updateinfo;    //显示版本号的tv控件    private TextView tv_splash_version;    //布局控件    private RelativeLayout r1_splash;    /**     * Called when the activity is first created.     */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        //设置无标题栏        requestWindowFeature(Window.FEATURE_NO_TITLE);        //设置全屏模式        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);        //设置局部,显示版本号        setContentView(R.layout.activity_splash);        r1_splash = (RelativeLayout)findViewById(R.id.r1_splash);        tv_splash_version = (TextView)findViewById(R.id.tv_splash_version);        tv_splash_version.setText("版本号:" + getVersion());        //显示渐进动画        AlphaAnimation aa = new AlphaAnimation(0.3f, 1.0f);        aa.setDuration(2000);        r1_splash.startAnimation(aa);        //检查更新        new Thread(new checkUpdate()) {        }.start();    }    //获取当前应用程序的版本号    private String getVersion() {        String version = "";        //获取系统包管理器        PackageManager pm = this.getPackageManager();        try {            PackageInfo info = pm.getPackageInfo(getPackageName(), 0);            version = info.versionName;        } catch (Exception e) {            e.printStackTrace();        }        return version;    }    /**     * 消息处理器     */    private Handler handler = new Handler() {         public void handleMessage(Message msg) {            switch (msg.what) {                case GET_INFO_SUCCESS:                    String serverVersion = updateinfo.getVersion();                    String currentVersion = getVersion();                    if (currentVersion.equals(serverVersion)) {                        Log.i(TAG, "版本号相同无需升级,直接进入主界面");                    }else {                        Log.i(TAG, "版本号不同需升级,显示升级对话框");                        showUpdateDialog();                    }                    break;                case SERVER_ERROR:                    Toast.makeText(getApplicationContext(), "服务器内部异常", 1).show();                    break;                case SERVER_URL_ERROR:                    Toast.makeText(getApplicationContext(), "服务器路径错误", 1).show();                    break;                case PROTOCOL_ERROR:                    Toast.makeText(getApplicationContext(), "协议错误", 1).show();                    break;                case XML_PARSER_ERROR:                    Toast.makeText(getApplicationContext(), "XML解析错误", 1).show();                    break;                case IO_ERROR:                    Toast.makeText(getApplicationContext(), "I/O错误", 1).show();                    break;                case UNKNOWN_ERROR:                    Toast.makeText(getApplicationContext(), "未知错误", 1).show();                    break;            }        }    };    /**     * 检查更新     */    private class checkUpdate implements Runnable {       public void run() {           long startTime = System.currentTimeMillis();           long endTime = startTime;           Message msg = Message.obtain();           try {               //获取服务器更新地址               String serverurl = getResources().getString(R.string.serverurl);               URL url = new URL(serverurl);               HttpURLConnection conn = (HttpURLConnection)url.openConnection();               conn.setRequestMethod("GET");               conn.setConnectTimeout(5000);               int code = conn.getResponseCode();               if (code == 200) {                   //success                   InputStream is = conn.getInputStream();                    //解析出更新信息                   updateinfo = UpdateInfoParser.getUpdateInfo(is);                   endTime = System.currentTimeMillis();                   long time = endTime - startTime;                   if (time < 2000) {                       try {                           Thread.sleep(2000 - time);                       } catch (InterruptedException e) {                           e.printStackTrace();                       }                   }                   msg.what = GET_INFO_SUCCESS;                   handler.sendMessage(msg);               } else {                   //服务器错误                   msg.what = SERVER_ERROR;                   handler.sendMessage(msg);                   endTime = System.currentTimeMillis();                   long time = endTime - startTime;                   if (time < 2000) {                       try {                           Thread.sleep(2000 - time);                       } catch (InterruptedException e) {                           e.printStackTrace();                       }                   }               }           } catch (MalformedURLException e) {               msg.what = SERVER_URL_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (ProtocolException e) {               msg.what = PROTOCOL_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (IOException e) {               msg.what = IO_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (XmlPullParserException e) {               msg.what = XML_PARSER_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           } catch (Exception e) {               msg.what = UNKNOWN_ERROR;               handler.sendMessage(msg);               e.printStackTrace();           }       }    }    /**     * 显示升级提示对话框     */    protected void showUpdateDialog() {        //创建对话框构造器        AlertDialog.Builder builder = new AlertDialog.Builder(this);        //设置对话框图标        builder.setIcon(getResources().getDrawable(R.drawable.notification));        //设置对话框标题        builder.setTitle("升级提示");        //设置更新信息为对话框提示内容        builder.setMessage(updateinfo.getDesc());        //设置升级按钮及响应事件        builder.setPositiveButton("升级", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialog, int which) {            }        });        //设置取消按钮及响应事件        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {            @Override            public void onClick(DialogInterface dialog, int which) {            }        });        //创建并显示对话框        builder.create().show();    }}

10、运行效果图

本地版本号与服务器版本号相同时直接进入主界面:

12-23 05:43:33.279    2125-2125/com.example.mobilesafe I/SplashActivity﹕ 版本号相同无需升级,直接进入主界面

本地版本号与服务器版本号不同时显示提示升级对话框:

12-23 05:44:37.349    2125-2125/com.example.mobilesafe I/SplashActivity﹕ 版本号不同需升级,显示升级对话框







0 0
原创粉丝点击