转自:http://blog.csdn.net/wh_19910525/article/details/8660416

Android的版本可以在androidmainfest.xml中定义,主要有android:versionCode和android:versionName

  • android:versionCode:主要是用于版本升级所用,是INT类型的,第一个版本定义为1,以后递增,这样只要判断该值就能确定是否需要升级,该值不显示给用户。
  • android:versionName:这个是我们常说明的版本号,由三部分组成<major>.<minor>.<point>,该值是个字符串,可以显示给用户。

关于版本号有两个值,如下面的例子

复制代码
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.xxx.xxx"    android:versionCode="2"    android:versionName="1.1">    ......
复制代码

versionCode是给设备程序识别版本(升级)用的,必须是一个interger值,整数,代表app更新过多少次

versionName是给用户看的,可以写1.1 , 1.2等等版本

延伸出另外一个问题:当app需要校对版本的时候怎样读取这个值?

1、读取manifest.xml

PackageManager pm = context.getPackageManager();//context为当前Activity上下文 PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);version = pi.versionName;

2、在里面定义android:versionName="@string/app_versionName"然后在 res/values/strings.xml 里定义一个同名 string item :<string name="app_versionName">1.1</string>

花开花谢春不管,水暖水寒鱼自知.

Android学习系列(2)--App自动更新之通知栏下载

见证过博客园的多次升级,你也希望你的软件通过更新发布新特性通知用户吧,是的。
这篇文章是android开发人员的必备知识,是我特别为大家整理和总结的,不求完美,但是有用。

1.设计思路,使用VersionCode定义为版本升级参数。
  android为我们定义版本提供了2个属性:

1 2 3 4 < manifest package="com.cnblogs.tianxia.subway" android:versionCode="1" <!--Integer类型,系统不显示给用户--> android:versionName="1.0" <!--String类型,系统显示用户--> ></ manifest >

谷歌建议我们使用versionCode自增来表明版本升级,无论是大的改动还是小的改动,而versionName是显示用户看的软件版本,作为显示使用。所以我们选择了VersionCode作为我们定义版本升级的参数。

2.工程目录
  为了对真实项目或者企业运用有实战指导作用,我模拟一个独立的项目,工程目录设置的合理严谨一些,而不是仅仅一个demo。
  假设我们以上海地铁为项目,命名为"Subway",工程结构如下,
android:versionCode和android:versionName 用途(转) App自动更新之通知栏下载_第1张图片

3.版本初始化和版本号的对比。
  首先定义在全局文件Global.java中定义变量localVersion和serverVersion分别存放本地版本号和服务器版本号。

1 2 3 4 5 6 public class Global { //版本信息 public static int localVersion = 0 ; public static int serverVersion = 0 ; public static String downloadDir = "app/download/" ; }

 因为本文只是重点说明升级更新,为了防止其他太多无关代码冗余其中,我直接在SubwayApplication中定义方法initGlobal()方法。

1 2 3 4 5 6 7 8 9 10 11 12 /** * 初始化全局变量 * 实际工作中这个方法中serverVersion从服务器端获取,最好在启动画面的activity中执行 */ public void initGlobal(){ try { Global.localVersion = getPackageManager().getPackageInfo(getPackageName(), 0 ).versionCode; //设置本地版本号 Global.serverVersion = 1 ; //假定服务器版本为2,本地版本默认是1 } catch (Exception ex){ ex.printStackTrace(); } }

如果检测到新版本发布,提示用户是否更新,我在SubwayActivity中定义了checkVersion()方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 /** * 检查更新版本 */ public void checkVersion(){ if (Global.localVersion < Global.serverVersion){ //发现新版本,提示用户更新 AlertDialog.Builder alert = new AlertDialog.Builder( this ); alert.setTitle( "软件升级" ) .setMessage( "发现新版本,建议立即更新使用." ) .setPositiveButton( "更新" , new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //开启更新服务UpdateService //这里为了把update更好模块化,可以传一些updateService依赖的值 //如布局ID,资源ID,动态获取的标题,这里以app_name为例 Intent updateIntent = new Intent(SubwayActivity. this , UpdateService. class ); updateIntent.putExtra( "titleId" ,R.string.app_name); startService(updateIntent); } }) .setNegativeButton( "取消" , new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); alert.create().show(); } else { //清理工作,略去 //cheanUpdateFile(),文章后面我会附上代码 } }

如下图:
android:versionCode和android:versionName 用途(转) App自动更新之通知栏下载_第2张图片
  好,我们现在把这些东西串一下:
  第一步在SubwayApplication的onCreate()方法中执行initGlobal()初始化版本变量

1 2 3 4 public void onCreate() { super .onCreate(); initGlobal(); }

第二步在SubwayActivity的onCreate()方法中检测版本更新checkVersion()。

1 2 3 4 5 public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); checkVersion(); }

  现在入口已经打开,在checkVersion方法的第18行代码中看出,当用户点击更新,我们开启更新服务,从服务器上下载最新版本。

4.使用Service在后台从服务器端下载,完成后提示用户下载完成,并关闭服务。
  定义一个服务UpdateService.java,首先定义与下载和通知相关的变量:

1 2 3 4 5 6 7 8 9 10 11 12 13 //标题 private int titleId = 0 ; //文件存储 private File updateDir = null ;   private File updateFile = null ; //通知栏 private NotificationManager updateNotificationManager = null ; private Notification updateNotification = null ; //通知栏跳转Intent private Intent updateIntent = null ; private PendingIntent updatePendingIntent = null ;

在onStartCommand()方法中准备相关的下载工作:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @Override public int onStartCommand(Intent intent, int flags, int startId) { //获取传值 titleId = intent.getIntExtra( "titleId" , 0 ); //创建文件 if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState())){ updateDir = new File(Environment.getExternalStorageDirectory(),Global.downloadDir); updateFile = new File(updateDir.getPath(),getResources().getString(titleId)+ ".apk" ); } this .updateNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); this .updateNotification = new Notification(); //设置下载过程中,点击通知栏,回到主界面 updateIntent = new Intent( this , SubwayActivity. class ); updatePendingIntent = PendingIntent.getActivity( this , 0 ,updateIntent, 0 ); //设置通知栏显示内容 updateNotification.icon = R.drawable.arrow_down_float; updateNotification.tickerText = "开始下载" ; updateNotification.setLatestEventInfo( this , "上海地铁" , "0%" ,updatePendingIntent); //发出通知 updateNotificationManager.notify( 0 ,updateNotification); //开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞 new Thread( new updateRunnable()).start(); //这个是下载的重点,是下载的过程 return super .onStartCommand(intent, flags, startId); }

上面都是准备工作,如图:

  从代码中可以看出来,updateRunnable类才是真正下载的类,出于用户体验的考虑,这个类是我们单独一个线程后台去执行的。
  下载的过程有两个工作:1.从服务器上下载数据;2.通知用户下载的进度。
  线程通知,我们先定义一个空的updateHandler。

1 2 3 4 5 6 private Handler updateHandler = new Handler(){ @Override public void handleMessage(Message msg) { } };

再来创建updateRunnable类的真正实现:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class updateRunnable implements Runnable { Message message = updateHandler.obtainMessage(); public void run() { message.what = DOWNLOAD_COMPLETE; try { //增加权限; if (!updateDir.exists()){ updateDir.mkdirs(); } if (!updateFile.exists()){ updateFile.createNewFile(); } //下载函数,以QQ为例子 //增加权限; long downloadSize = downloadUpdateFile( "http://softfile.3g.qq.com:8080/msoft/179/1105/10753/MobileQQ1.0(Android)_Build0198.apk" ,updateFile); if (downloadSize> 0 ){ //下载成功 updateHandler.sendMessage(message); } } catch (Exception ex){ ex.printStackTrace(); message.what = DOWNLOAD_FAIL; //下载失败 updateHandler.sendMessage(message); } } }

下载函数的实现有很多,我这里把代码贴出来,而且我们要在下载的时候通知用户下载进度:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception { //这样的下载代码很多,我就不做过多的说明 int downloadCount = 0 ; int currentSize = 0 ; long totalSize = 0 ; int updateTotalSize = 0 ; HttpURLConnection httpConnection = null ; InputStream is = null ; FileOutputStream fos = null ; try { URL url = new URL(downloadUrl); httpConnection = (HttpURLConnection)url.openConnection(); httpConnection.setRequestProperty( "User-Agent" , "PacificHttpClient" ); if (currentSize > 0 ) { httpConnection.setRequestProperty( "RANGE" , "bytes=" + currentSize + "-" ); } httpConnection.setConnectTimeout( 10000 ); httpConnection.setReadTimeout( 20000 ); updateTotalSize = httpConnection.getContentLength(); if (httpConnection.getResponseCode() == 404 ) { throw new Exception( "fail!" ); } is = httpConnection.getInputStream(); fos = new FileOutputStream(saveFile, false ); byte buffer[] = new byte [ 4096 ]; int readsize = 0 ; while ((readsize = is.read(buffer)) > 0 ){ fos.write(buffer, 0 , readsize); totalSize += readsize; //为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次 if ((downloadCount == 0 )||( int ) (totalSize* 100 /updateTotalSize)- 10 >downloadCount){ downloadCount += 10 ; updateNotification.setLatestEventInfo(UpdateService. this , "正在下载" , ( int )totalSize* 100 /updateTotalSize+ "%" , updatePendingIntent); updateNotificationManager.notify( 0 , updateNotification); } } } finally { if (httpConnection != null ) { httpConnection.disconnect(); } if (is != null ) { is.close(); } if (fos != null ) { fos.close(); } } return totalSize; }

显示下载进度,如图:
android:versionCode和android:versionName 用途(转) App自动更新之通知栏下载_第3张图片
下载完成后,我们提示用户下载完成,并且可以点击安装,那么我们来补全前面的Handler吧。
先在UpdateService.java定义2个常量来表示下载状态:

1 2 3 //下载状态 private final static int DOWNLOAD_COMPLETE = 0 ; private final static int DOWNLOAD_FAIL = 1 ;

根据下载状态处理主线程:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private Handler updateHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case DOWNLOAD_COMPLETE: //点击安装PendingIntent Uri uri = Uri.fromFile(updateFile); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.setDataAndType(uri, "application/vnd.android.package-archive" ); updatePendingIntent = PendingIntent.getActivity(UpdateService. this , 0 , installIntent, 0 ); updateNotification.defaults = Notification.DEFAULT_SOUND; //铃声提醒 updateNotification.setLatestEventInfo(UpdateService. this , "上海地铁" , "下载完成,点击安装。" , updatePendingIntent); updateNotificationManager.notify( 0 , updateNotification); //停止服务 stopSelf(); break ; case DOWNLOAD_FAIL: //下载失败 updateNotification.setLatestEventInfo(UpdateService. this , "上海地铁" , "下载完成,点击安装。" , updatePendingIntent); updateNotificationManager.notify( 0 , updateNotification); break ; default : stopSelf(); } } };

下载完成,如图:
android:versionCode和android:versionName 用途(转) App自动更新之通知栏下载_第4张图片
至此,文件下载并且在通知栏通知进度。
发现本人废话很多,其实几句话的事情,来来回回写了这么多,啰嗦了,后面博文我会朝着精简方面努力。
PS:前面说要附上cheanUpdateFile()的代码

1 2 3 4 5 File updateFile = new File(Global.downloadDir,getResources().getString(R.string.app_name)+ ".apk" ); if (updateFile.exists()){ //当不需要的时候,清除之前的下载文件,避免浪费用户空间 updateFile.delete(); }

谢谢大家!!!!

分类: Android学习系列

更多相关文章

  1. Android 自定义View之坐标系(一)
  2. Android自定义视图一:扩展现有的视图,添加新的XML属性
  3. Android 中自定义View(四)
  4. Android之——自定义TextView
  5. Akita 一套Android快速开发库 发布1.2版本
  6. Android 中自定义View(三)
  7. Android 中自定义View(一)
  8. Android 中自定义View(二)

随机推荐

  1. Android开发资源完全汇总
  2. Android(安卓)沉浸式状态栏 头部可拉伸带
  3. android下解析xml文件遇到中文问题
  4. Android中原生Progress几种常用的风格
  5. Binder---- Android(安卓)的IPC 通信机制
  6. Android阶段性总结(2011/9/6)
  7. Android(安卓)Handler 异步消息处理机制
  8. Android(安卓)是什么
  9. Android(安卓)中的微型云
  10. Android自动化测试之Monkey工具