Android 轻松实现后台搭建+APP版本更新

http://blog.csdn.net/u012422829/article/details/46355515

(本文讲解了在Android中实现APP版本更新,文末附有源码。)

看完本文,您可以学到:

1.版本更新的方法

2.与后台的交互

3.Android中Handler的使用

4.Android中ProgressDialog的使用

话不多说,先来看看效果图:

一、大致思路阐述

首先,我们要有一个可以被手机访问的后台。

这里有两种方法,在调试的时候我们可以利用手机和笔记本连到同一个局域网的方式,在电脑上开启个类似PHP或者JAVAEE一样样的后台服务。

但是对于没有相关后台开发经验的朋友,这里有一种更好的方式:利用Github等免费空间来实现。详细请戳我的另一篇博文利用Github建立你的个人网站 。

OK,有了存放资源的后台,我们要放点什么东西呢?很简单,一个包含最新版本信息的update.txt文件和一个.apk文件足矣!

txt文件里写啥?看下我的例子:

XXX&1.3&这里写点描述&http://192.168.1.100:8080/PersonalHomePage/new.apk

解释一下: &是分隔符,用于手机端获取到信息后的分割。1.3代表着最新版本号,之后的是新版本的描述,最后的是新版本APK的下载地址(这里我用了局域网)。一开始的是啥呢?我当时在试验的时候,在开头并没有加额外信息,即以1.3开头,实验之后,发现手机端获取到TXT文本信息后不能正确解析,原因我觉得是因为TXT文件的开头包含有一些自带的字符,手机解析时会有问题。(感兴趣的朋友可以去深究,还望不吝赐教!)

OK,有了新版本的信息,我们要怎么做?

我们要获取到最新的版本号,然后与当前APP的版本号进行对比。如果低于最新版本,就到下载地址中去下载。

二、详细代码解释

首先,新建一个UpdateInfo类,用来与update.txt的内容对应,这个很简单:

[java] view plain copy

  1. package com.example.appupdatedemo;
  2. public class UpdateInfo
  3. {
  4. private String version;
  5. private String description;
  6. private String url;
  7. public String getVersion()
  8. {
  9. return version;
  10. }
  11. public void setVersion(String version)
  12. {
  13. this.version = version;
  14. }
  15. public String getDescription()
  16. {
  17. return description;
  18. }
  19. public void setDescription(String description)
  20. {
  21. this.description = description;
  22. }
  23. public String getUrl()
  24. {
  25. return url;
  26. }
  27. public void setUrl(String url)
  28. {
  29. this.url = url;
  30. }
  31. }

然后,写一个类去获取更新的信息,即我们的update.txt文件:

UpdateInfoService:

[java] view plain copy

  1. package com.example.appupdatedemo;
  2. import java.io.BufferedReader;
  3. import java.io.InputStreamReader;
  4. import java.net.HttpURLConnection;
  5. import java.net.URL;
  6. import android.content.Context;
  7. public class UpdateInfoService {
  8. public UpdateInfoService(Context context) {
  9. }
  10. public UpdateInfo getUpDateInfo() throws Exception {
  11. String path = GetServerUrl.getUrl() + "/update.txt";
  12. StringBuffer sb = new StringBuffer();
  13. String line = null;
  14. BufferedReader reader = null;
  15. try {
  16. // 创建一个url对象
  17. URL url = new URL(path);
  18. // 通過url对象,创建一个HttpURLConnection对象(连接)
  19. HttpURLConnection urlConnection = (HttpURLConnection) url
  20. .openConnection();
  21. // 通过HttpURLConnection对象,得到InputStream
  22. reader = new BufferedReader(new InputStreamReader(
  23. urlConnection.getInputStream()));
  24. // 使用io流读取文件
  25. while ((line = reader.readLine()) != null) {
  26. sb.append(line);
  27. }
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. } finally {
  31. try {
  32. if (reader != null) {
  33. reader.close();
  34. }
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. }
  38. }
  39. String info = sb.toString();
  40. UpdateInfo updateInfo = new UpdateInfo();
  41. updateInfo.setVersion(info.split("&")[1]);
  42. updateInfo.setDescription(info.split("&")[2]);
  43. updateInfo.setUrl(info.split("&")[3]);
  44. return updateInfo;
  45. }
  46. }

这里获取文件的方法是先创建一个HttpURLConnection,再获取输入流。细心的朋友可能注意到其中有个类,叫GetServerUrl,这个类是用来存放后台地址信息的:

[java] view plain copy

  1. package com.example.appupdatedemo;
  2. /**
  3. * 获取服务器IP地址
  4. */
  5. public class GetServerUrl{
  6. static String url="http://192.168.1.100:8080/PersonalHomePage";   //没错,我这里用的是本地的JAVAEE工程,各位根据实际情况修改。
  7. public static String getUrl() {
  8. return url;
  9. }
  10. }

OK,到了这一步,准备工作都做完了,接下来只剩一个类了!即我们的MainActicity,一共一百多行,我们分几部分来讲。

第一部分代码,做的工作是获取版本更新信息。

[java] view plain copy

  1. public class MainActivity extends Activity {
  2. // 更新版本要用到的一些信息
  3. private UpdateInfo info;
  4. private ProgressDialog pBar;
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView(R.layout.activity_main);
  9. Toast.makeText(MainActivity.this, "正在检查版本更新..", Toast.LENGTH_SHORT).show();
  10. // 自动检查有没有新版本 如果有新版本就提示更新
  11. new Thread() {
  12. public void run() {
  13. try {
  14. UpdateInfoService updateInfoService = new UpdateInfoService(
  15. MainActivity.this);
  16. info = updateInfoService.getUpDateInfo();
  17. handler1.sendEmptyMessage(0);
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. };
  22. }.start();
  23. }
  24. @SuppressLint("HandlerLeak")
  25. private Handler handler1 = new Handler() {
  26. public void handleMessage(Message msg) {
  27. // 如果有更新就提示
  28. if (isNeedUpdate()) {   //在下面的代码段
  29. showUpdateDialog();  //下面的代码段
  30. }
  31. };
  32. };

这里我们用到了new Thread+ Handler的方式去进行异步加载版本信息,主要是因为在安卓中要把耗时任务放在非主线程中执行,否则会造成阻塞,抛出无响应异常。还有另外的实现方式是安卓封装的AsyncTask,具体可以参考这篇博文:Android AsyncTask详解

第二部分,判断是否是最新版本,如果不是,跳出对话框选择是否更新:

[java] view plain copy

  1. private void showUpdateDialog() {
  2. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  3. builder.setIcon(android.R.drawable.ic_dialog_info);
  4. builder.setTitle("请升级APP至版本" + info.getVersion());
  5. builder.setMessage(info.getDescription());
  6. builder.setCancelable(false);
  7. builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
  8. @Override
  9. public void onClick(DialogInterface dialog, int which) {
  10. if (Environment.getExternalStorageState().equals(
  11. Environment.MEDIA_MOUNTED)) {
  12. downFile(info.getUrl());     //在下面的代码段
  13. } else {
  14. Toast.makeText(MainActivity.this, "SD卡不可用,请插入SD卡",
  15. Toast.LENGTH_SHORT).show();
  16. }
  17. }
  18. });
  19. builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
  20. @Override
  21. public void onClick(DialogInterface dialog, int which) {
  22. }
  23. });
  24. builder.create().show();
  25. }
  26. private boolean isNeedUpdate() {
  27. String v = info.getVersion(); // 最新版本的版本号
  28. Log.i("update",v);
  29. Toast.makeText(MainActivity.this, v, Toast.LENGTH_SHORT).show();
  30. if (v.equals(getVersion())) {
  31. return false;
  32. } else {
  33. return true;
  34. }
  35. }
  36. // 获取当前版本的版本号
  37. private String getVersion() {
  38. try {
  39. PackageManager packageManager = getPackageManager();
  40. PackageInfo packageInfo = packageManager.getPackageInfo(
  41. getPackageName(), 0);
  42. return packageInfo.versionName;
  43. } catch (NameNotFoundException e) {
  44. e.printStackTrace();
  45. return "版本号未知";
  46. }
  47. }

这段里面要注意的是怎么获取当前版本,方法是使用PackageManager提供的getPackageInfo方法,返回的是manifest文件中的版本号。其他的代码挺简单,注释也挺全的。如果有问题,欢迎留言。

接下来是最后一部分,下载文件。

[java] view plain copy

  1. void downFile(final String url) {
  2. pBar = new ProgressDialog(MainActivity.this);    //进度条,在下载的时候实时更新进度,提高用户友好度
  3. pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
  4. pBar.setTitle("正在下载");
  5. pBar.setMessage("请稍候...");
  6. pBar.setProgress(0);
  7. pBar.show();
  8. new Thread() {
  9. public void run() {
  10. HttpClient client = new DefaultHttpClient();
  11. HttpGet get = new HttpGet(url);
  12. HttpResponse response;
  13. try {
  14. response = client.execute(get);
  15. HttpEntity entity = response.getEntity();
  16. int length = (int) entity.getContentLength();   //获取文件大小
  17. pBar.setMax(length);                            //设置进度条的总长度
  18. InputStream is = entity.getContent();
  19. FileOutputStream fileOutputStream = null;
  20. if (is != null) {
  21. File file = new File(
  22. Environment.getExternalStorageDirectory(),
  23. "Test.apk");
  24. fileOutputStream = new FileOutputStream(file);
  25. byte[] buf = new byte[10];   //这个是缓冲区,即一次读取10个比特,我弄的小了点,因为在本地,所以数值太大一 下就下载完了,看不出progressbar的效果。
  26. int ch = -1;
  27. int process = 0;
  28. while ((ch = is.read(buf)) != -1) {
  29. fileOutputStream.write(buf, 0, ch);
  30. process += ch;
  31. pBar.setProgress(process);       //这里就是关键的实时更新进度了!
  32. }
  33. }
  34. fileOutputStream.flush();
  35. if (fileOutputStream != null) {
  36. fileOutputStream.close();
  37. }
  38. down();
  39. } catch (ClientProtocolException e) {
  40. e.printStackTrace();
  41. } catch (IOException e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. }.start();
  46. }
  47. void down() {
  48. handler1.post(new Runnable() {
  49. public void run() {
  50. pBar.cancel();
  51. update();
  52. }
  53. });
  54. }
  55. //安装文件,一般固定写法
  56. void update() {
  57. Intent intent = new Intent(Intent.ACTION_VIEW);
  58. intent.setDataAndType(Uri.fromFile(new File(Environment
  59. .getExternalStorageDirectory(), "Test.apk")),
  60. "application/vnd.android.package-archive");
  61. startActivity(intent);
  62. }

这一段主要是利用progressdialog在下载的时候实时更新进度,主要利用的是一个字节数组的缓冲区。即每次获取到的内容填满缓冲区后就写入到本地本件中。这里我把缓冲区的大小设置为10个字节(1024会比较好),理由是因为在同一个局域网中速度特别快,刷一下就下载完了,看不出进度条效果,缓冲区调小点就OK了。

========================================

写在后面:

源代码已上传到我的Github,或者到CSDN下载区下载。

任何问题,欢迎留言交流!

时间: 2024-12-20 08:42:10

Android 轻松实现后台搭建+APP版本更新的相关文章

Android 关于后台杀死App之后改变服务器状态的一些尝试

前言: 如题,我的需求是:我需要在App在后台运行(未退出),调出最近运行记录,杀死App服务时,程序能够向服务器发送一条指令,以此达到我想要的目的. Android方面刚刚才开始玩,我一开始想的是可不可以在Activity中监听到,比如onDestroy()方法,但是打Log看了之后是没有的.度娘是万能的,百度一波后,我在逼乎上找到了另一个思路,那就是创建一个Server,很多人的博客中也都指出了,App在后台被杀死时,Service的onTaskRemoved()方法是可以监听到的. Ser

微信app支付(android端+java后台)

本文讲解使用微信支付接口完成在android开发的原生态app中完成微信支付功能, 文章具体讲解了前端android如何集成微信支付功能以及后台如何组装前端需要支付信息, 话不多话, 具体看文章内容吧00:00 / 07:03正常 本实例项目运行条件: 开发环境: [Android Studio] 到微信开放平台注册帐号并且创建移动应用 https://open.weixin.qq.com/cgi-bin/frame?t=home/app_tmpl&lang=zh_CN Column 1 Col

Android自动化测试-UiAutomator环境搭建

Android自动化测试-UiAutomator环境搭建 一.环境准备 1. 安装android sdk,并配置环境变量 2. 安装android studio,国内访问官网受限,如果下载不到,可以到我的百度云盘下载: https://pan.baidu.com/s/1bpq5wK3 此云盘中有uiautomator2所依赖的jar包,可以同时下载 二.新建Android Studio工程 新建一个project,输入application name,下一步, 默认选择,下一步, 选择 empt

Android Junit测试环境搭建

一.单元测试简介 在android的开发的过程中,经常需要对业务方面的代码进行测试,熟悉java的人都知道junit, 在android中google提供了基于junit为android进行了优化得自动化框架junit,在Junit中可以得到组件,可以模拟发送事件和检测程序处理的正确性,在java中使用junit编写测试用例,我们需要继承TestCase,在android中需要继承AndroidTestCase. 二.环境搭建 1. 业务类 业务类中写了add函数,Junit来测试add函数的正

安卓实战之如何快速搭建app架构

前言 最近公司的另一个项目又要立项了,作为公司的唯一安卓工程师任务来了(新来的移动端的老大说项目还是主要你负责,我就负责帮你们安排下进度),听了这话我是伤心的在这公司不管是几个还是1个安卓开发都是我来搭建,干着与工资不符的事情,好的一点是开发没有人干涉平时也能学习自己想学的东西. 如何选择app架构(MVC/MVP/MVVM) 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解MVP,但是还是觉得比较牛逼,然后呢也想在公司的项目中去使用它. 项目时间紧迫:快速开

Android ADB工具-管理设备 app(二)

Android ADB工具-管理设备 app(二) 标签(空格分隔): Android 4.管理设备 app 命令 功能 adb install [-r|-s] <apkfile> 安装 apk 文件 adb uninstall [-k] <packagename> 卸载 app adb shell top [-m <number>] 查看内存占用情况 adb shell ps 查看进程列表 adb shell kill <pid> 杀死一个进程 adb s

android + eclipse + 后台静默安装(一看就会)

首先要说到三个类. [java] view plaincopy import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageInstallObserver$Stub; import android.content.pm.PackageManager; 其中,IPackageInstallObserver和IPackageInstallObserver$Stub 这两个类,在android

【Android自学之旅】 Android开发环境的搭建

搭建参考教程: http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html http://www.cnblogs.com/bjzhanghao/archive/2012/11/14/2769409.html 下载开发工具 Jave SDK: http://www.oracle.com/technetwork/java/javase/downloads/index.html Android

APP版本更新通知流程测试要点

一.APP版本更新通知流程图如下: 二.测试注意点: 1.Android更新直接下载APK,IOS引导至APP Store更新页面: 强制更新------只有"立即更新" 1.一般"强制更新"的机制不常用,除非涉及到APP的紧急且致命缺陷的修复,或者是与用户monkey密切相关的问题,或许才会使用"强制更新"机制: 2.不点击"立即更新"则APP中无法使用.更新后使用正常 提醒更新-------立即更新 1.Android同意