- 浏览: 812455 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
wa19912002:
感谢 tomcat8改成7就好了
jstl的错误总结与解决方法 -
呵呵6666:
不错,谢谢分享!推荐个参考视频内容:http://www.ro ...
浅谈mysql主从复制的高可用解决方案 -
masuweng:
tabindex的微妙使用 -
syxfqw7:
完全正确,补充一下<beans:bean id=&quo ...
SpringSecurity3.1.2控制一个账户同时只能登录一次 -
fireinjava:
longToip直接用ipToLong反过来就好了 publi ...
IP地址与长整数之间的转换详解
1、之前写过一篇说版本升级的,用到广播。感觉乱用,搞的有点复杂,且混乱。现在又用到了版本升级功能,然后梳理下思路,使用回调接口重新写了个。
2、需求同http://aokunsang.iteye.com/blog/1487429,部分源码已上传。
3、增加了点小功能:
1>、可以手动检查升级;
2>、显示升级日志;
3>、修改上篇博客潜在问题:
问题:后台查询到更新,提示更新的AlertDialog只能在启动更新的页面弹出;如果离开此页面,抛异常。
解决:在app的所有页面顶层弹出,参考代码:
//设置dialog dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); //加入权限 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
4、截图如下:
5、上代码(代码才能说明一切):
(1)、DownloadCallback.java
/** * 下载数据接口 * @author: aokunsang * @date: 2012-12-17 */ public interface DownloadCallback { /** * 下载前准备 */ public void onDownloadPreare(); /** * 下载进度更新 * @param progress 进度值 */ public void onChangeProgress(int progress); /** * 下载完成 * @param success 下载成功标示 * @param errorMsg 下载失败显示内容 */ public void onCompleted(boolean success,String errorMsg); /** * 取消下载 */ public boolean onCancel(); }
(2)、DownloadInstall.java
/** * @author: aokunsang * @date: 2012-12-18 */ public class DownloadInstall implements DownloadCallback { private Context mContext; private String apkPath,apkVersion; private int apkCode; private LayoutInflater inflater; private TextView textView; private ProgressBar progressView; private AlertDialog downloadDialog; //下载弹出框 private boolean interceptFlag = false; //是否取消下载 public DownloadInstall(Context mContext,String apkPath,String apkVersion,int apkCode) { this.mContext = mContext; this.apkCode = apkCode; this.apkPath = apkPath; this.apkVersion = apkVersion; inflater = LayoutInflater.from(mContext); } @Override public boolean onCancel() { return interceptFlag; } @Override public void onChangeProgress(int progress) { progressView.setProgress(progress); //设置下载进度 textView.setText("进度:"+progress+"%"); } @Override public void onCompleted(boolean success, String errorMsg) { if(downloadDialog!=null){ downloadDialog.dismiss(); } if(success){ //更新成功 alearyUpdateSuccess(); installApk(); }else{ Toast.makeText(mContext, errorMsg, Toast.LENGTH_SHORT).show(); } } @Override public void onDownloadPreare() { if(IntentUtil.checkSoftStage(mContext)){ File file = new File(Const.apkSavepath); if(!file.exists()){ file.mkdir(); } Builder builder = new AlertDialog.Builder(mContext); builder.setIcon(R.drawable.upgrade).setTitle("正在更新版本"); //---------------------------- 设置在对话框中显示进度条 -------------------- View view = inflater.inflate(R.layout.upgrade_apk, null); textView = (TextView)view.findViewById(R.id.progressCount_text); textView.setText("进度:0"); progressView = (ProgressBar)view.findViewById(R.id.progressbar); builder.setView(view); builder.setNegativeButton("取消", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); interceptFlag = true; } }); downloadDialog = builder.create(); downloadDialog.show(); } } /** * 升级成功,更新升级日期和版本号,和版本code */ private void alearyUpdateSuccess(){ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); SharedPreferences sharedPreference = mContext.getSharedPreferences(UpdateShared.SETTING_UPDATE_APK_INFO, 0); sharedPreference.edit().putString(UpdateShared.UPDATE_DATE, sdf.format(new Date())) .putString(UpdateShared.APK_VERSION, apkVersion).putInt(UpdateShared.APK_VERCODE, apkCode).commit(); } /** * 安装apk */ private void installApk(){ File file = new File(apkPath); if(!file.exists()){ return; } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); mContext.startActivity(intent); } }
(3)、DownloadAsyncTask.java
/** * 异步下载数据 * @author: aokunsang * @date: 2012-12-17 */ public class DownloadAsyncTask extends AsyncTask<String, Integer, String> { private DownloadCallback downCallBack; private HttpURLConnection urlConn; public DownloadAsyncTask(DownloadCallback downloadCallback){ this.downCallBack = downloadCallback; } @Override protected void onPreExecute() { downCallBack.onDownloadPreare(); super.onPreExecute(); } @Override protected String doInBackground(String... args) { String apkDownloadUrl = args[0]; //apk下载地址 String apkPath = args[1]; //apk在sd卡中的安装位置 String result = ""; if(!IntentUtil.checkURL(apkDownloadUrl)){ result = "netfail"; }else{ InputStream is = null; FileOutputStream fos = null; try { URL url = new URL(apkDownloadUrl); urlConn = (HttpURLConnection)url.openConnection(); is = urlConn.getInputStream(); int length = urlConn.getContentLength(); //文件大小 fos = new FileOutputStream(apkPath); int count = 0,numread = 0; byte buf[] = new byte[1024]; while(!downCallBack.onCancel()&& (numread = is.read(buf))!=-1){ count+=numread; int progressCount =(int)(((float)count / length) * 100); publishProgress(progressCount); fos.write(buf, 0, numread); } fos.flush(); result = "success"; } catch (Exception e) { e.printStackTrace(); result = "fail"; }finally{ try { if(fos!=null) fos.close(); if(is!=null) is.close(); } catch (IOException e) { e.printStackTrace(); result = "fail"; } } } return result; } @Override protected void onProgressUpdate(Integer... values) { downCallBack.onChangeProgress(values[0]); super.onProgressUpdate(values); } @Override protected void onPostExecute(String result) { if(downCallBack.onCancel()){ downCallBack.onCompleted(false, "版本更新下载已取消。"); }else if("success".equals(result)){ downCallBack.onCompleted(true, null); }else if("netfail".equals(result)){ downCallBack.onCompleted(false, "连接服务器失败,请稍后重试。"); }else{ downCallBack.onCompleted(false, "版本更新失败,请稍后重试。"); } super.onPostExecute(result); } @Override protected void onCancelled() { if(urlConn!=null){ urlConn.disconnect(); } super.onCancelled(); } }
(4)、DownloadManager.java
/** * 下载管理 * @author: aokunsang * @date: 2012-12-18 */ public class DownloadManager{ private Context mContext; final static int CHECK_FAIL = 0; final static int CHECK_SUCCESS = 1; final static int CHECK_NOUPGRADE = 2; final static int CHECK_NETFAIL = 3; private ApkInfo apkinfo; private AlertDialog noticeDialog; //提示弹出框 private ProgressDialog progressDialog; private boolean isAccord; //是否主动检查软件升级 private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); public DownloadManager(Context mContext,boolean isAccord){ this.mContext = mContext; this.isAccord = isAccord; } Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { if(progressDialog!=null){ progressDialog.dismiss(); } switch(msg.what){ case CHECK_SUCCESS:{ showNoticeDialog(); break; } case CHECK_NOUPGRADE:{ //不需要更新 if(isAccord) Toast.makeText(mContext, "当前版本是最新版。", Toast.LENGTH_SHORT).show(); break; } case CHECK_NETFAIL:{ if(isAccord) Toast.makeText(mContext, "网络连接不正常。", Toast.LENGTH_SHORT).show(); break; } case CHECK_FAIL:{ if(isAccord) Toast.makeText(mContext, "从服务器获取更新数据失败。", Toast.LENGTH_SHORT).show(); break; } } }; }; /* 检查下载更新 [apk下载入口] */ public void checkDownload(){ if(isAccord) progressDialog = ProgressDialog.show(mContext, "", "请稍后,正在检查更新..."); new Thread() { @Override public void run() { if(!IntentUtil.isConnect(mContext)){ //检查网络连接是否正常 handler.sendEmptyMessage(CHECK_NETFAIL); }else if(checkTodayUpdate() || isAccord){//判断今天是否已自动检查过更新 ;如果手动检查更新,直接进入 String result = HttpRequestUtil.getSourceResult(Const.apkCheckUpdateUrl, null, mContext); try { //从服务器下载数据有中文,所以服务器对数据进行了编码;在这里需要解码 result = Escape.unescape(result); JSONObject obj = new JSONObject(result); String apkVersion = obj.getString("apkVersion"); int apkCode = obj.getInt("apkVerCode"); String apkSize = obj.getString("apkSize"); String apkName = obj.getString("apkName"); String downloadUrl = obj.getString("apkDownloadUrl"); String apkLog = obj.getString("apklog"); apkinfo = new ApkInfo(downloadUrl, apkVersion, apkSize, apkCode, apkName, apkLog); if(apkinfo!=null && checkApkVercode()){ //检查版本号 alreayCheckTodayUpdate(); //设置今天已经检查过更新 handler.sendEmptyMessage(CHECK_SUCCESS); }else{ handler.sendEmptyMessage(CHECK_NOUPGRADE); } } catch (Exception e) { e.printStackTrace(); handler.sendEmptyMessage(CHECK_FAIL); } } } }.start(); } /* 弹出软件更新提示对话框*/ private void showNoticeDialog(){ StringBuffer sb = new StringBuffer(); sb.append("版本号:"+apkinfo.getApkVersion()+"\n") .append("文件大小:"+apkinfo.getApkSize()+"\n") .append("更新日志:\n"+apkinfo.getApkLog()); Builder builder = new AlertDialog.Builder(mContext); builder.setIcon(R.drawable.upgrade).setTitle("版本更新").setMessage(sb.toString()); builder.setPositiveButton("下载", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { String apkPath = Const.apkSavepath + apkinfo.getApkName(); DownloadCallback downCallback = new DownloadInstall(mContext, apkPath, apkinfo.getApkVersion(), apkinfo.getApkCode()); DownloadAsyncTask request = new DownloadAsyncTask(downCallback); request.execute(apkinfo.getDownloadUrl(),apkPath); dialog.dismiss(); } }); builder.setNegativeButton("以后再说", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); noticeDialog = builder.create(); noticeDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); //设置最顶层Alertdialog noticeDialog.show(); } /** * 根据日期检查是否需要进行软件升级 * @throws Exception */ private boolean checkTodayUpdate() { SharedPreferences sharedPreference = mContext.getSharedPreferences(UpdateShared.SETTING_UPDATE_APK_INFO, 0); String checkDate = sharedPreference.getString(UpdateShared.CHECK_DATE, ""); String updateDate = sharedPreference.getString(UpdateShared.UPDATE_DATE, ""); if("".equals(checkDate) && "".equals(updateDate)){ //刚安装的新版本,设置详细信息 int verCode = IntentUtil.getCurrentVersionCode(mContext); String versionName = IntentUtil.getCurrentVersionName(mContext); String dateStr = sdf.format(new Date()); sharedPreference.edit().putString(UpdateShared.CHECK_DATE, dateStr) .putString(UpdateShared.UPDATE_DATE, dateStr) .putString(UpdateShared.APK_VERSION, versionName) .putInt(UpdateShared.APK_VERCODE, verCode).commit(); return true; } try { //判断defaultMinUpdateDay天内不检查升级 if((new Date().getTime()-sdf.parse(updateDate).getTime())/1000/3600/24<Const.defaultMinUpdateDay){ return false; }else if(checkDate.equalsIgnoreCase(sdf.format(new Date()))){//判断今天是否检查过升级 return false; } } catch (Exception e) { e.printStackTrace(); return false; } return true; } /** * 设置今天已经检查过升级 * @return */ private void alreayCheckTodayUpdate(){ String date = sdf.format(new Date()); SharedPreferences sharedPreference = mContext.getSharedPreferences(UpdateShared.SETTING_UPDATE_APK_INFO, 0); sharedPreference.edit().putString(UpdateShared.CHECK_DATE, date).commit(); } /** * 检查版本是否需要更新 * @return */ private boolean checkApkVercode(){ SharedPreferences sharedPreference = mContext.getSharedPreferences(UpdateShared.SETTING_UPDATE_APK_INFO, 0); int verCode = sharedPreference.getInt(UpdateShared.APK_VERCODE, 0); if(apkinfo.getApkCode()>verCode){ return true; }else{ return false; } } static interface UpdateShared{ String SETTING_UPDATE_APK_INFO = "cbt_upgrade_setting"; String UPDATE_DATE = "updatedate"; String APK_VERSION = "apkversion"; String APK_VERCODE = "apkvercode"; String CHECK_DATE = "checkdate"; } }
代码内容我不讲解,使用的是回调接口。里面的各种检查是否升级,参考上一篇软件更新博客http://aokunsang.iteye.com/blog/1487429。
(5)、其他操作类:
a、Const.java是一个常量存储类,保存检查更新地址等;
b、Escape.java是个URL解码编码类;
c、HttpRequestUtil.java获取远程数据类;
d、IntentUtil.java工具类,如:检查网络连接状态等。
(以上类参考附件源码)
/** * apk更新信息 * @author: aokunsang * @date: 2012-12-18 */ public class ApkInfo implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String downloadUrl; //下载地址 private String apkVersion; //apk版本 private String apkSize; //apk文件大小 private int apkCode; //apk版本号(更新必备) private String apkName; //apk名字 private String apkLog; //apk更新日志 setter and getter... }
(6)、服务器代码(这里的apklog可以是个txt文档,在UI上下载展示,我做的比较简单):
/** * 获取apk更新信息 * {apkVersion:'1.10',apkSize:'36K',apkVerCode:2,apkName:'1.1.apk',apkDownloadUrl:'http://localhost:8080/myapp/1.1.apk',apklog:'1、修改页面;\n2、修改字体'} */ @Action(value="checkUpdateApk") public String updateApk(){ ResourceLoader loader = new DefaultResourceLoader(); Properties pp = null; try { InputStream is = loader.getResource("classpath:config/sysconf.properties").getInputStream(); pp = new Properties(); pp.load(new InputStreamReader(is, "utf-8")); } catch (Exception e) { e.printStackTrace(); } if(pp!=null){ String apkVersion = pp.getProperty("apkVersion"); String apkDownloadUrl = pp.getProperty("apkDownloadUrl"); String apkName = pp.getProperty("apkName"); int apkVerCode = NumberUtils.toInt(pp.getProperty("apkVerCode"),0); String apklog = pp.getProperty("apkLog"); String apkSize = pp.getProperty("apkSize"); Httptear.ResponseResultByEscape("{apkVersion:'"+apkVersion+"',apkSize:'"+apkSize+"',apkVerCode:"+apkVerCode+",apkName:'"+apkName+"',apkDownloadUrl:'"+apkDownloadUrl+"',apklog:'"+apklog+"'}"); }else{ Httptear.ResponseResultByEscape("{}"); } return NONE; }
6、upgrade_apk.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/progressCount_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="@color/white" android:textSize="14dip" /> <ProgressBar android:id="@+id/progressbar" style="?android:attr/progressBarStyleHorizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
7、需要加入以下权限:
<!-- 在SD卡中创建和删除文件权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <!-- 向SD卡中写入东西权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
8、启动更新检查代码:
/* 升级程序[主动] (因为会弹出一个ProgressDialog窗口,不能使用getApplicationContext())*/ DownloadManager downManger = new DownloadManager(this,true); downManger.checkDownload();
/* 升级程序启动[被动](使用this引用会导致:如在1页面启动升级,当前页面为2页面,此时弹出Dialog抛异常)*/ DownloadManager downManger = new DownloadManager(getApplicationContext(),false); downManger.checkDownload();
评论
这个不科学,重新下载试试。
这是很久以前做android项目时候的blog,现在已不做android很多年。
哦 谢谢
这是很久以前做android项目时候的blog,现在已不做android很多年。
项目工程没法公开,只能根据该文章结合理解实现。如有问题,可发出来共同解决。
亲,你下载下来放项目中不能使用么。 这就好比一个可插拔的控件,放项目中都能用的啊。
发表评论
-
gridview图片展示,长按进入编辑模式
2012-08-31 14:53 13940看到小米手机和其他一些图片显示软件,gridview显示 ... -
Android-ExifInterface如何正确存取Double类型坐标
2012-08-10 15:08 47721、向图片中存储一些属性,可以使用ExifInter ... -
Android软件的自动更新
2012-04-16 12:47 13932今天重新写了一篇 ... -
Android拍照,上传,预览综合【修改】
2011-12-07 14:21 32916最近需要做手机 ... -
百度地图的手动定位和自动定位
2011-07-07 18:45 52468最近由于项目需要,研究了下百度地图定位, ... -
android资源文件详细介绍
2011-07-01 13:45 3540摘自:http://blog.csdn.net/sayyanf ... -
谈Activity的生命周期
2011-07-01 13:42 1761摘自:http://blog.csdn.net/wyh0802 ... -
Android开发调试时logcat不显示问题
2011-07-01 13:40 2194摘自:http://dev.10086.cn/cmdn/wik ... -
AndroidManifest.xml详细介绍
2011-07-01 13:30 1794以下摘自网上,只为记录学习。 一、关于Andro ...
相关推荐
Android软件自动更新升级功能的实现,可以直接放到项目中
很多的Android应用都具有版本检测和自动更新的功能,用户一键就可以完成软件的升级和更新。Android应用程序的升级本质上是利用了Linux系统的软件包管理和安装机制,而对于上层这一功能的开发来说很容易,只需要我们...
Android应用自动更新代码实现,完美实现代码的自动更新。
Delphi XE android 更新 升级 自动 在线更新升级APP 然后自动安装的代码实现
android版本自动更新安装 替换旧的apk
Android应用实现自动更新功能,用户一键就可以完成软件的升级更新。通过http连接tomcat7测试。
Android 应用软件自动更新源码.rar
android应用软件自动更新源码 自动更新源码
获取服务器端XML文件,解析XML获取到最新版本号,与当前软件版本号进行对比,发现不一样则提示更新。 涉及到内容点: 1.远程获取XML并分析XML内容 2.远程下载文件并打开 3.下载时通知栏显示下载进度
Android中的软件的自动更新(包括静默更新,需Root权限),详细了解请移步:http://blog.csdn.net/zxc514257857/article/details/77504010
Android_-_软件自动更新的实现 实例代码完整可用.
android 程序自动更新功能设计,我们在开发软件后需要后续维护更新版本,但是你不能指望使用者绝对按照的你要求来操作,所以自动更新非常重要。
此代码主要作用是实现android apk/软件自动更新
网上找了一堆Delphi安卓APP程序自动升级方法都大多不太好用,有的需要配置WEB服务器,有的控制下载和升级管理麻烦,于是综合网上资料,根据项目需要整理了一个代码单元,可以直接调用,测试环境Delphi XE 10.3
Android APP应用的自动升级更新,可以在本地或连接HTTP进行自动检测,提示是否升级,自动安装。
android版本更新 demo 版本更新 系统更新 自动升级
NULL 博文链接:https://913.iteye.com/blog/2039633
【搞定】xamarin.android自动升级,非常推荐使用和下载
非强制更新方式 强制更新方式 自动下载 快速安装