Android 版本检测、文件下载并更新
来源:互联网 发布:数据库安全管理办法 编辑:程序博客网 时间:2024/06/01 08:18
前言:
一个软件想要长期的发展,必须经过更新这个过程。版本检测、版本提示并自动更新并安装这过程是必不可少的。近阶段刚做了一个项目,项目中也有更新这个需求,所以就记录一下,希望能帮到别人。
一、版本检测
如果是Eclpse开发工具,在自己的项目中的AndroidManifest.xml配置文件中,可以找到两个参数,一个是versionCode和versionName。versionCode表示版本代码,是整型。versionName表示版本名称,是字符串。升级的时候,可以检查versionCode,也可以检查versionName。我这里是使用了versionName。因为涉及到小版本的更新和大版本更新。比较方法下面会贴出代码。
Eclipse:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hjy.demo" android:versionCode="1" android:versionName="1.0.0" >
如果是AS的开发工具,那么versionCode和versionName是在app文件下的build.gradle
文件中。
Android studio:
defaultConfig { applicationId "com.smarthx.projectassistant" minSdkVersion 14 targetSdkVersion 23 versionCode 1 versionName "1.0.0"}
通过上面配置代码版本以及名称,接下来就有一个问题,就是如何在java代码中获取这些参数呢?
/** * 获取当前包名信息 * 这些信息是从相对应的Androdimanifest.xml * @param context * @return */private static PackageInfo getPackageInfo(Context context) { PackageInfo pi = null; try { PackageManager pm = context.getPackageManager(); pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_CONFIGURATIONS); return pi; } catch (Exception e) { e.printStackTrace(); } return pi;}/*** 版本名* @param context* @return*/public static String getVersionName(Context context) { return getPackageInfo(context).versionName;}/*** 版本号* @param context* @return*/public static int getVersionCode(Context context) { return getPackageInfo(context).versionCode;}
通过这些方法可以获取到版本代码以及版本名称,通过服务器(java写的)拉取数据,匹配服务器的版本和当前APP的版本是否是一致的(比如:服务器versionName 是1.0.1,本地versionName是1.0.0),不一致做更新动作。versionName匹配代码如下:
/*** 比较版本号的大小,前者大则返回一个正数,后者大返回一个负数,相等则返回0* @param version1* @param version2* @return*/public static int compareVersion(String version1, String version2) throws Exception { if (version1 == null || version2 == null) { throw new Exception(); } 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;}
上面compareVersion方法可以根据返回值去执行动作,如果输入参数version2是当前APP版本名称,version1是远程服务器版本名称,输出返回值为正数时,那么就要做更新动作,输出返回值为负数或者为0时,那么就不做任何动作。至于更新的动作,就是向服务器发起一个请求,该请求就是下载最新版本的apk,然后安装并取代旧版本。
二、文件下载
这里的下载使用AsyncTask(android提供的轻量级的异步类)做下载动作。这里为了开发方便,将一些公共的函数,单独放在UpgradeTask类中实现,代码如下:
/*** 下载文件工具类* @author hjy* created at 2016/12/9 15:14*/public class UpgradeTask extends AsyncTask<String, Integer, String> { private static final int TIME_OUT = 25000; Context context; private static final int NOTIFY_ID = 12345; private NotificationManager mNotifyMgr; private RemoteViews views; private Notification nofity; private VersionInfo verInfo; private String APK_FILE_NAME ; private int fileLen; public UpgradeTask(Context context,String APK_FILE_NAME,int fileLen){ this.context =context; this.APK_FILE_NAME =APK_FILE_NAME; this.fileLen = fileLen; } @Override protected void onPreExecute() { showNotify(); } protected String doInBackground(String... params) { //Log.d("test","开始下载···"); InputStream is = null; FileOutputStream fos = null; try { URL url = new URL(params[0]); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); // conn.getContentLength()// 注意,虚拟地址不能使用这个方法获得文件大小 // 为http请求设置超时时间 conn.setConnectTimeout(TIME_OUT); conn.setReadTimeout(TIME_OUT); if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {// ToastUtils.showToast(context, "服务端正在维护");// Toast.makeText(context, "服务端正在维护", Toast.LENGTH_SHORT).show(); return null; } is = conn.getInputStream(); // conn.getContentLength() File upgradeApk = new File(APK_FILE_NAME); if (!upgradeApk.exists()) { upgradeApk.getParentFile().mkdirs(); } fos = new FileOutputStream(upgradeApk); byte[] buffer = new byte[1024]; int loadedLen = 0; int len = 0; int count = 0; while (-1 != (len = is.read(buffer))) { fos.write(buffer, 0, len); loadedLen += len; int perc = loadedLen * 100 / fileLen; // 每1%更新一次 if (perc > 1 * count){ count++; publishProgress(loadedLen); } } fos.flush(); } catch (SocketTimeoutException e) { // 处理超时事件 } catch (MalformedURLException e) { } catch (IOException e) { } finally { if (is != null) { try { is.close(); } catch (IOException e) { } } if (fos != null) { try { fos.close(); } catch (IOException e) { } } } //Log.d("test","开始完成···"); return null; } @Override protected void onProgressUpdate(Integer... values) { updateNotify(values[0]); } protected void onPostExecute(String result) { // 提示安装apk// ToastUtils.showToast(context, "下载完成,请点击通知安装"); Toast.makeText(context, "下载完成,请点击通知安装", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(APK_FILE_NAME)), "application/vnd.android.package-archive"); context.startActivity(intent); finishNotify(); //SPUtils.writeIsUpgrade(MyApp.context, false); } /** * 通知栏初始化 * @author hjy * created at 2016/12/8 11:38 */ private void showNotify() { mNotifyMgr = (NotificationManager) context.getSystemService( Context.NOTIFICATION_SERVICE); Intent intent = new Intent(); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0); views = new RemoteViews(context.getPackageName(), R.layout.custom_notify); views.setTextViewText(R.id.textView1, "准备下载"); views.setTextViewText(R.id.textView2, ""); views.setProgressBar(R.id.progressBar1, 10, 0, false); nofity = new NotificationCompat.Builder(context) .setSmallIcon(R.mipmap.icon_shanchu_focused) .setTicker("开始更新...") .setWhen(System.currentTimeMillis()) // .setContentTitle("contentTitle") // .setContentText("contentText") .setAutoCancel(true).setContent(views) .setContentIntent(contentIntent).build(); mNotifyMgr.notify(NOTIFY_ID, nofity); } /** * 更新中 * @author hjy * created at 2016/12/8 11:38 */ private void updateNotify(int currLen) { views.setTextViewText(R.id.textView1, currLen * 100 / fileLen + "%"); views.setProgressBar(R.id.progressBar1, fileLen, currLen, false); mNotifyMgr.notify(NOTIFY_ID, nofity); } /** * 更新完毕 * @author hjy * created at 2016/12/8 11:37 */ private void finishNotify() { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(new File(APK_FILE_NAME)), "application/vnd.android.package-archive"); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0); nofity.contentIntent = contentIntent; views.setTextViewText(R.id.textView1, "下载完成,点击更新"); views.setImageViewResource(R.id.imageView1,R.mipmap.ic_launcher); views.setViewVisibility(R.id.progressBar1, View.INVISIBLE); mNotifyMgr.notify(NOTIFY_ID, nofity); } public void setVersionInfo(VersionInfo verInfo) { this.verInfo = verInfo; }}
通知栏的布局文件custom_notify.xml文件如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/RelativeLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" android:orientation="vertical" android:background="#FFFFFF" > <ImageView android:id="@+id/imageView1" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginRight="12dp" android:scaleType="fitXY" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_toRightOf="@+id/imageView1" android:text="Medium Text" android:textColor="@color/mainStyle" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/imageView1" android:layout_alignLeft="@+id/textView1" android:textColor="#000000" android:text="TextView" /> <ProgressBar android:id="@+id/progressBar1" style="?android:attr/progressBarStyleHorizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/textView2" android:layout_alignParentRight="true" android:layout_toRightOf="@+id/textView2" /></RelativeLayout>
通过调用以下该方法即可实现文件下载:
/*** 下载文件* @author hjy* @param updateUrl APP下载地址* @param appPath APP下载缓存路径* @param fileLength 文件总大小(progress总长度)* created at 2016/12/8 14:37*/private void loadFile(String updateUrl,String appPath,int fileLength){ UpgradeTask task = new UpgradeTask(LoginActivity.this, appPath, fileLength); task.execute(updateUrl);}
通过以上UpgradeTask工具类调用execute方法去实现文件下载,有需要的小伙伴,可以直接拿去使用。如果有出错或者需要改进的地方,欢迎指点或者交流。
0 0
- Android 版本检测、文件下载并更新
- Android从服务器检测更新并下载
- Android 检测版本更新
- Android检测版本更新
- Android检测版本更新
- Android检测版本更新
- Android 版本检测更新
- android检测版本更新
- Android版本检测更新
- Android检测版本更新
- Android版本检测更新
- Android检测版本更新
- Android版本检测更新
- android客户端版本检测更新,服务下载,通知栏显示
- android客户端版本检测更新,服务下载,通知栏显示
- android 客户端版本检测更新,服务下载,通知栏显示
- Android应用检测并下载更新新版本的方法
- Android----- 版本更新和 服务器下载新版本APK并安装
- 密码算法体制
- EasyUI Tree 树
- Hadoop学习笔记(一)
- 四道Java基础题 你能对几道?
- 友盟推送集成的常见问题
- Android 版本检测、文件下载并更新
- 2016/11/30
- BZOJ 3940 AC自动机
- 【Python机器学习】梯度下降法(三) 优矿(uqer.io)
- 113. Path Sum II 这里要注意 引用 和 传值的区别,见注释
- 网络请求runloop
- Two Day(2)---运算符
- R语言实战笔记--第一章 R的安装配置及使用
- JAVA实现打印机打印字符串