android APP版本检测升级

1、本次服务端采用的是HTTP Servlet方式返回json数据

首先建立一个javaweb工程 创建一个Servlet类,代码在doGet中实现

/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		// response.getWriter().append("Served at:
		// ").append(request.getContextPath());	
		HttpSession session = request.getSession();
		String str = request.getParameter("function");
		if (str == null) {
			str = "main";
		}
		// 判断session是不是新创建的 减少读取xml频次
		if (session.isNew()) {
			//System.out.println("session创建成功,session的id是:" + session.getId());
		} else {
			//System.out.println("服务器已经存在该session了,session的id是:" + session.getId());
			String function = session.getAttribute("function").toString();
			//判断功能是否一致
			if (function.equals(str)) {
				String data = session.getAttribute("data").toString();
				response.setCharacterEncoding("utf-8");
				response.getWriter().append(data);
				return;
			}			
		}
		session.setAttribute("function", str.toString());
		if (str != null && str.equals("你的APP别名")) {//function代表你的APP,支持多个APP版本更新,放在不同的xml里面
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = null;
			try {
				db = dbf.newDocumentBuilder();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String path = this.getServletContext().getRealPath("version2.xml");
			File file = new File(path);
			InputStream is = new FileInputStream(file);

			org.w3c.dom.Document doc = null;
			try {
				doc = db.parse(is);
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Element elem = ((org.w3c.dom.Document) doc).getDocumentElement();
			JSONObject jsonObjectRoot = new JSONObject();
			NodeList appversion = elem.getChildNodes();
			if (appversion != null) {
				JSONObject jsonObjectUpdate = new JSONObject();
				int n = 0;// 更新条目
				for (int i = 0; i < appversion.getLength(); i++) {
					Node app = appversion.item(i);
					for (Node node = app.getFirstChild(); node != null; node = node.getNextSibling()) {
						if (app.getNodeName().equals("version")) {
							String ver = app.getFirstChild().getNodeValue();
							jsonObjectRoot.put("version", ver);
						}
						if (app.getNodeName().equals("date")) {
							String da = app.getFirstChild().getNodeValue();
							jsonObjectRoot.put("date", da);
						}
						if (app.getNodeName().equals("update")) {
							n++;
							String ud = app.getFirstChild().getNodeValue();
							jsonObjectUpdate.put(n + "", ud);
						}
						if (app.getNodeName().equals("address")) {
							String addr = app.getFirstChild().getNodeValue();
							jsonObjectRoot.put("address", addr);
						}
					}
				}
				jsonObjectRoot.put("update", jsonObjectUpdate);
			}
			response.setCharacterEncoding("utf-8");
			response.getWriter().append(jsonObjectRoot.toString());
			session.setAttribute("data", jsonObjectRoot.toString());
		} else {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = null;
			try {
				db = dbf.newDocumentBuilder();
			} catch (ParserConfigurationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String path = this.getServletContext().getRealPath("version.xml");
			File file = new File(path);
			InputStream is = new FileInputStream(file);

			org.w3c.dom.Document doc = null;
			try {
				doc = db.parse(is);
			} catch (SAXException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Element elem = ((org.w3c.dom.Document) doc).getDocumentElement();
			JSONObject jsonObjectRoot = new JSONObject();
			NodeList appversion = elem.getChildNodes();
			if (appversion != null) {
				JSONObject jsonObjectUpdate = new JSONObject();
				int n = 0;// 更新条目
				for (int i = 0; i < appversion.getLength(); i++) {
					Node app = appversion.item(i);
					for (Node node = app.getFirstChild(); node != null; node = node.getNextSibling()) {
						if (app.getNodeName().equals("version")) {
							String ver = app.getFirstChild().getNodeValue();
							jsonObjectRoot.put("version", ver);
						}
						if (app.getNodeName().equals("date")) {
							String da = app.getFirstChild().getNodeValue();
							jsonObjectRoot.put("date", da);
						}
						if (app.getNodeName().equals("update")) {
							n++;
							String ud = app.getFirstChild().getNodeValue();
							jsonObjectUpdate.put(n + "", ud);
						}
						if (app.getNodeName().equals("address")) {
							String addr = app.getFirstChild().getNodeValue();
							jsonObjectRoot.put("address", addr);
						}
					}
				}
				jsonObjectRoot.put("update", jsonObjectUpdate);
			}
			response.setCharacterEncoding("utf-8");
			response.getWriter().append(jsonObjectRoot.toString());
			session.setAttribute("data", jsonObjectRoot.toString());
		}
	}
将XML文件放在WebContent目录下,结构自己定义,例如我的version.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<appupdate>
	<title>XX系统</title>
	<version>1.1.0</version>
	<date>2018.02.04</date>
	<update>1:XXX优化</update>
	<update>2:XXX修改</update>
	<update>3:XXX增加</update>
	<update>4:XXX其他</update>	
	<address>http://1.1.1.1:8888/download/YourApp.apk</address><!--你更新的APP的下载地址-->
</appupdate>
APP下载地址你可以放到tamcat服务器的一个虚拟下载目录下,搜索tomcat搭建文件下载服务器,很简单的配置。

这样访问地址 http://1.1.1.1:8888/YourWebName/YourServletName?function=你的APP别名 就能得到一个json字符串,例如我的如下:
{"version":"1.1.0","date":"2018.02.04","address":"http://1.1.1.1:8888/download/YourApp.apk","update":{"1":"1:XXX优化","2":"2:XXX修改","3":"3:XXX增加","4":"4:XXX其他"}}
现在web服务器端已经完成,下面进行android端编写

2、android客户端
   一、建立一个版本更新类,如下
public class AppVersion extends AsyncTask<String, integer, StringBuffer> {
    private Handler handle;

    public String getVersion() {
        return version;
    }

    private String version = "";

    public String getUpdate() {
        return update;
    }

    private String update = "";

    private String updateURL = "";

    static private String updateAPKname = "";

    static public String getAPKname() {
        return updateAPKname;
    }
    private boolean bAuto = true;

    public AppVersion(Handler handle, boolean bAuto/*自动检查更新、手动检查更新*/) {
        this.handle = handle;
        this.bAuto = bAuto;
    }

    @Override
    protected StringBuffer doInBackground(String... params) {
        String html = "";
        try {
            //HTTP GET请求
            URL url = null;
            url = new URL(params[0]);        
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(2000);
            conn.setReadTimeout(1000);
            InputStream inStream = conn.getInputStream();
            byte[] data = readInputStream(inStream);
            html = new String(data, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new StringBuffer(html);
    }

    public static byte[] readInputStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        inStream.close();
        return outStream.toByteArray();
    }

    @Override
    protected void onPostExecute(StringBuffer result) {
        String Html = new String(result);
        if (!Html.equals("")) {
            try {
                JSONObject jsonObjectRoot = new JSONObject(Html);
                version = jsonObjectRoot.getString("version");
                JSONObject jsonObjectUpdate = jsonObjectRoot.getJSONObject("update");
                Iterator<String> keys = jsonObjectUpdate.keys();
                while (keys.hasNext()) {
                    String key = (String) keys.next();
                    update = update + jsonObjectUpdate.getString(key) + "\r\n\r\n";
                }
                updateURL = jsonObjectRoot.getString("address");
                updateAPKname = updateURL.substring(updateURL.lastIndexOf("/") + 1);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            handle.sendEmptyMessage(4);
        } else {
            if (!bAuto)
                Toast.makeText(SearchApplication.getInstance(), "无法获取更新,请检查网络是否畅通", Toast.LENGTH_LONG).show();
        }
        super.onPostExecute(result);
    }

    public String getUpdateURL() {
        return updateURL;
    }

    public boolean isbAuto() {
        return bAuto;
    }

    public void setbAuto(boolean bAuto) {
        this.bAuto = bAuto;
    }
}
二、在MainActivity的onCreate方法中调用

     

private String path = "http://1.1.1.1:8888/YourWebName/YourServletName?function=你的APP别名";
private AppVersion appVersion
private MyHandler myHandler;
appVersion = new AppVersion(myHandler, true);
appVersion.execute(path);
public class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {              
            case 4://查询更新返回
                try {
                    if (compareVersion(appVersion.getVersion(), getVersion()) > 0) {
                        //获得最后版本后,如果服务器版本>当前版本,则显示更新内容 只提示1次,1次后在菜单显示
                        String csTipUpdate = sp.getString(Constant.csTipUpdate, "0");//获取是否提示过
                        //如果未提示或者是手动更新的 则显示更新弹窗
                        if (csTipUpdate.equals("0") || !appVersion.isbAuto()) {
                            showUpdateDialog(true);//显示更新的弹窗
                            sp.edit().putString(Constant.csTipUpdate, "1").apply();
                        }
                        bUpdate = true;//菜单标志位
                        btnDowloadMap.setImageResource(R.mipmap.set1);
                    } else {
                        Log.d("version:", "没有更新的版本!");
                        sp.edit().putString(Constant.csTipUpdate, "0").apply();
                        //获得最后版本后,如果和当前不一致,则显示更新内容
                        String csVersion = sp.getString(Constant.csVersion, "");
                        if (csVersion.equals("") || !csVersion.equals(appVersion.getVersion())) {
                            showUpdateDialog(false);//显示内容
                        }
                        sp.edit().putString(Constant.csVersion, appVersion.getVersion()).apply();
                        if (!appVersion.isbAuto())
                            Toast.makeText(MainActivity.this, "无可用更新", Toast.LENGTH_LONG).show();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;  
            case 8://下载进度
            double percent = queryDownloadStatus();
            if (progressBar_download != null)
                progressBar_download.setProgress((int) percent);
            if (percent >= 100)
                progressBar_download.setVisibility(View.INVISIBLE);
            break;          
        }
    }
}
/**
* 比较版本号的大小,前者大则返回一个正数,后者大返回一个负数,相等则返回0
*
* @param version1
* @param version2
*/
public static int compareVersion(String version1, String version2) throws Exception {
    if (version1 == null || version2 == null) {
        throw new Exception("compareVersion error:illegal params.");
    }
    String[] versionArray1 = version1.split("\\.");//注意此处为正则匹配,不能用.;
    String[] versionArray2 = version2.split("\\.");
    int idx = 0;
    int minLength = Math.min(versionArray1.length, versionArray2.length);//取最小长度值
    int diff = 0;
    while (idx < minLength
            && (diff = versionArray1[idx].length() - versionArray2[idx].length()) == 0//先比较长度
            && (diff = versionArray1[idx].compareTo(versionArray2[idx])) == 0) {//再比较字符
        ++idx;
    }
    //如果已经分出大小,则直接返回,如果未分出大小,则再比较位数,有子版本的为大;
    diff = (diff != 0) ? diff : versionArray1.length - versionArray2.length;
    return diff;
}
 
/**
* Author:
* CreateTime: 2017/11/15 11:09
* Comment: 获取软件版本号
* Param:
*/
public String getVersion() {
    try {
        PackageManager manager = this.getPackageManager();
        PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
        String version = info.versionName;
        return version;
    } catch (Exception e) {
        String s = e.toString();
        e.printStackTrace();
        return "";
    }
}

三、android端下载APK安装

private DownloadManager downloadManager;//下载管理类
private long lastDownloadId;
/**
* Author: 
* CreateTime: 2018/1/3 15:39
* Comment: 更新窗口
* Param:
*/

private void showUpdateDialog(boolean b) {
    if (b) {
        LayoutInflater inflater = LayoutInflater.from(this);
        View layout = inflater.inflate(R.layout.pop_needupdate, null);//资源文件不贴出了
        final Dialog dialog = new Dialog(MainActivity.this, R.style.dialogstyle);
        TextView tv = (TextView) layout.findViewById(R.id.tvupdate);//显示内容的文件控件
        final TextView tvdownload = (TextView) layout.findViewById(R.id.btn_download);//下载按钮
        TextView tvclose = (TextView) layout.findViewById(R.id.btn_close);//弹窗关闭按钮
        tvclose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });
        tvdownload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
                Uri uri = Uri.parse(appVersion.getUpdateURL());//更新类获得的APK URL地址
                DownloadManager.Request request = new DownloadManager.Request(uri);
                request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
                request.setVisibleInDownloadsUi(false);
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
                File rootFile = new File(Environment.getExternalStorageDirectory().getPath() + "/YourAPP/download/");//创建一个下载目录
                if (!rootFile.exists()) {
                    rootFile.mkdirs();
                }
                request.setDestinationInExternalPublicDir("/YourAPP/download/", getAPKname());//设置下载路径
                lastDownloadId = downloadManager.enqueue(request);
                app.setLastDownloadId(lastDownloadId);
                progressBar_download.setVisibility(View.VISIBLE);//弹窗上的下载进度条
                tvdownload.setText("正在下载");
                tvdownload.setClickable(false);
                final Timer timer = new Timer();
                TimerTask task = new TimerTask() {
                    @Override
                    public void run() {
                        double percent = queryDownloadStatus();
                        myHandler.sendEmptyMessage(8);
                        if (percent >= 100) {
                            timer.cancel();
                        }
                    }
                };
                timer.schedule(task, 100, 500);
            }
        });
        progressBar_download = (CustomLoading) layout.findViewById(R.id.progressBar_download);
        String update = appVersion.getUpdate();
        tv.setText(update);
        dialog.setCancelable(false);
        dialog.setContentView(layout);
        dialog.show();

        Window window = dialog.getWindow();
        WindowManager manager = window.getWindowManager();
        Display d = manager.getDefaultDisplay();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = (int) (d.getWidth() * 0.4);
        params.height = LinearLayout.LayoutParams.WRAP_CONTENT;
        dialog.getWindow().setAttributes(params);
    } else {
        LayoutInflater inflater = LayoutInflater.from(this);
        View layout = inflater.inflate(R.layout.pop_update, null);//更新后软件第一次进入显示本次更新内容弹窗
        final Dialog dialog = new Dialog(MainActivity.this, R.style.dialogstyle);
        TextView tv = (TextView) layout.findViewById(R.id.tvupdate);
        String update = appVersion.getUpdate();
        tv.setText(update);
        dialog.setCancelable(true);
        dialog.setContentView(layout);
        dialog.show();
        Window window = dialog.getWindow();
        WindowManager manager = window.getWindowManager();
        Display d = manager.getDefaultDisplay();
        WindowManager.LayoutParams params = window.getAttributes();
        params.width = (int) (d.getWidth() * 0.4);
        params.height = LinearLayout.LayoutParams.WRAP_CONTENT;
        dialog.getWindow().setAttributes(params);
    }
}
//你的Application加入代码
public static YourApplication app;

private long lastDownloadId;

public static YourApplication getInstance() {
    return app;
}

public long getLastDownloadId() {
    return lastDownloadId;
}

public void setLastDownloadId(long lastDownloadId) {
    this.lastDownloadId = lastDownloadId;
}
//查询下载进度
private int queryDownloadStatus() {
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(lastDownloadId);
    Cursor c = downloadManager.query(query);
    if (c != null && c.moveToFirst()) {
        int fileSizeIdx = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
        int bytesDLIdx = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
        int fileSize = c.getInt(fileSizeIdx);
        int bytesDL = c.getInt(bytesDLIdx);
        double percent = bytesDL * 100.0 / fileSize;
        return (int) percent;
    }
    return 0;
}
四、加入一个广播,下载完成后安装
      AndroidManifest.xml加入如下代码

<!-- 权限下载更新时不在通知栏显示 其他网络权限就不贴出来了-->
    <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />

    </application>
        <receiver android:name=".BroadcastReceiver.CompleteReceiver">
            <intent-filter>
                <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
            </intent-filter>
        </receiver>
    </application>
广播类

public class CompleteReceiver extends BroadcastReceiver {

    private DownloadManager downloadManager;
    private long downloadId;

    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();
        if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
            downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
            installApk(context, downloadId);
        }
    }

    private void installApk(Context context, long downloadId) {
        DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
        if (app.getLastDownloadId() == downloadId) {
            Uri downloadFileUri = downloadManager.getUriForDownloadedFile(downloadId);
            if (getAPKname() != null && !getAPKname().equals("")) {
                try {
                    if (downloadFileUri != null) {
                        Intent install = new Intent(Intent.ACTION_VIEW);
                        install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive");
                        install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        context.startActivity(install);
                    }
                } catch (Exception e) {
                    Toast.makeText(context, "安装APP出现问题", Toast.LENGTH_LONG).show();
                }
            } else {
                Toast.makeText(context, "安装APP出现问题", Toast.LENGTH_LONG).show();
            }
        }
    }
}
好的,这里已经结束,学习安卓几个月时间,有不足写的不对的地方敬请见谅!


猜你喜欢

转载自blog.csdn.net/woshileihuanji/article/details/79252273