- 浏览: 816094 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
wa19912002:
感谢 tomcat8改成7就好了
jstl的错误总结与解决方法 -
呵呵6666:
不错,谢谢分享!推荐个参考视频内容:http://www.ro ...
浅谈mysql主从复制的高可用解决方案 -
masuweng:
tabindex的微妙使用 -
syxfqw7:
完全正确,补充一下<beans:bean id=&quo ...
SpringSecurity3.1.2控制一个账户同时只能登录一次 -
fireinjava:
longToip直接用ipToLong反过来就好了 publi ...
IP地址与长整数之间的转换详解
今天重新写了一篇自动更新的文章,参考:http://aokunsang.iteye.com/blog/1750440。本篇文章的源码整理了下,上传到了附件,需要的去下载。
看了几个博客,讲自动升级的程序,但是感觉都不是很完整,因为项目需要,自己手动写了个自动更新的程序,备忘下(本篇博客源码不上传了,免得误入歧途,需要源码的去新写的博客下载)。
一、 需求:如下图流程所示,需要在后台检查APK是否需要升级,需要升级则弹出提示下载升级对话框,用户点击下载进行升级,然后自动安装。
软件下载流程图:
二、 思路:APK自动检查是否升级,这个当然需要在后台进行。因此需要使用异步线程操作,想到IntentService和AsyncTask。
三、选择原因:使用IntentService异步检查升级,但是无法提示弹出对话框;因此需要使用广播通知BroadcastReceiver。但是我想直接在异步类中直接弹出下载对话框,IntentService没有提供Context这样的参数;并且需要提供一个异步检查升级,一个异步下载,需要两个IntentService,而IntentService是可以执行多个任务的,客户端只需通过startService(Intent) 方法调用,那么intentService就一个接着一个的顺序来处理。那么我要是建立两个IntentService类,有点大材小用。那就使用AsyncTask类吧,每个任务启动一个新的asycnTask来工作,一个asyncTask只能使用一次。正好符合我的要求。
四、执行顺序:时序图就不画了,说下类的执行流程吧。
1>mainActivity(主UI),
2>UpdateReceiver(更新广播通知),
3>CheckUpdateAsyncTask(检查更新),
4>UpdateAsyncTask(下载APK)
进入mainActivity,注册UpdateReceiver,同时执行CheckUpdateAsyncTask;检查完更新,由CheckUpdateAsyncTask广播通知UpdateReceiver,
UpdateReceiver的onReceive(Context,Intent)接收广播,并且启动UpdateAsyncTask下载。
五、代码展示:
1、mainActivity.java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ............. //注册一个广播 IntentFilter intentFilter = new IntentFilter(UpdateReceiver.ACTION_PROCRESS); intentFilter.addCategory(Intent.CATEGORY_DEFAULT); //添加一个Category属性,CheckUpdateAsyncTask发送广播时候也要添加该属性。保持遥相呼应 receiver = new UpdateReceiver(); registerReceiver(receiver, intentFilter); //启动后台异步执行检查更新 CheckUpdateAsyncTask checkAsyncTask = new CheckUpdateAsyncTask(WholeMainActivity.this); checkAsyncTask.execute(10); } }
2、CheckUpdateAsyncTask.java
/** * 检查是否有更新 * @author: aokunsang * @date: 2012-4-13 */ public class CheckUpdateAsyncTask extends AsyncTask<Integer, Integer, String> { private Context mContext; private final static String NOTE = "亲,有最新的软件包,赶紧下载吧~"; private final static String SETTING_UPDATE_APK_INFO = "setting_updateapkinfo"; private final static String CHECK_DATE = "checkdate"; private final static String UPDATE_DATE = "updatedate"; private final static String APK_VERSION = "apkversion"; private final static String APK_VERCODE = "apkvercode"; private AlertDialog noticeDialog; //提示弹出框 private UpdateApkInfo apkInfo; private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); public CheckUpdateAsyncTask(Context mContext){ this.mContext= mContext; } @Override protected String doInBackground(Integer... params) { String result = ""; //检查是否能够连接网络,根据日期判断是否需要进行更新 if(checkTodayUpdate() && PeaceUtil.isNetworkAvailable(mContext)){ getUpateApkInfo(); if(apkInfo!=null && checkApkVersion()){ //检查版本号 alreayCheckTodayUpdate(); //设置今天已经检查过更新 result = "success"; }else{ Log.i("---------检查应用更新-------------", "从服务器获取下载数据失败或者该版本code不需要升级"); result = "fail"; } }else{ Log.i("---------检查应用更新-------------", "无法连接网络或者根据日期判断不需要更新软件"); result = "fail"; } return result; } @Override protected void onCancelled() { // TODO Auto-generated method stub super.onCancelled(); } @Override protected void onPostExecute(String result) { if("success".equals(result)){ showNoticeDialog(); } super.onPostExecute(result); } /** * 弹出软件更新提示对话框 */ private void showNoticeDialog(){ Builder builder = new AlertDialog.Builder(mContext); builder.setTitle("软件版本更新").setMessage(NOTE); builder.setPositiveButton("下载", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(); intent.setAction(UpdateReceiver.ACTION_PROCRESS); intent.addCategory(Intent.CATEGORY_DEFAULT); //一定要添加这个属性,不然onReceive(Context,Intent)中的Context参数不等于mContext,并且报错 intent.putExtra(UpdateReceiver.PARAM_IN, apkInfo); dialog.dismiss(); mContext.sendBroadcast(intent); } }); builder.setNegativeButton("以后再说", new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); noticeDialog = builder.create(); noticeDialog.show(); } /** * 获取升级APK详细信息 * {apkVersion:'1.10',apkVerCode:2,apkName:'1.1.apk',apkDownloadUrl:'http://localhost:8080/myapp/1.1.apk'} * @return */ private void getUpateApkInfo(){ String updateApkJson = NetWorkAction.getnetworkInfo(mContext, Const.checkUpdateApk, null); updateApkJson = Escape.unescape(updateApkJson); try { JSONObject obj = new JSONObject(updateApkJson); String apkVersion = obj.getString("apkVersion"); int apkVerCode = obj.getInt("apkVerCode"); String apkName = obj.getString("apkName"); String apkDownloadUrl = obj.getString("apkDownloadUrl"); apkInfo = new UpdateApkInfo(apkVersion, apkName, apkDownloadUrl, apkVerCode); } catch (JSONException e) { e.printStackTrace(); } } /** * 根据日期检查是否需要进行软件升级 * @throws Exception */ private boolean checkTodayUpdate() { SharedPreferences sharedPreference = mContext.getSharedPreferences(SETTING_UPDATE_APK_INFO, 0); String checkDate = sharedPreference.getString(CHECK_DATE, ""); String updateDate = sharedPreference.getString(UPDATE_DATE, ""); Log.i("-------------------checkDate------------","检查时间:"+checkDate); Log.i("-------------------updateDate------------","最近更新软件时间:"+updateDate); if("".equals(checkDate) && "".equals(updateDate)){ //刚安装的新版本,设置详细信息 int verCode = 0; String versionName = ""; try { verCode = mContext.getPackageManager().getPackageInfo("com.peacemap.sl.jyg", 0).versionCode; versionName = mContext.getPackageManager().getPackageInfo("com.peacemap.sl.jyg", 0).versionName; } catch (NameNotFoundException e) { e.printStackTrace(); } String dateStr = sdf.format(new Date()); sharedPreference.edit().putString(CHECK_DATE, dateStr) .putString(UPDATE_DATE, dateStr) .putString(APK_VERSION, versionName) .putInt(APK_VERCODE, verCode).commit(); return false; } 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 boolean checkApkVersion(){ SharedPreferences sharedPreference = mContext.getSharedPreferences(SETTING_UPDATE_APK_INFO, 0); int verCode = sharedPreference.getInt(APK_VERCODE, 0); if(apkInfo.getAplVerCode()>verCode){ //如果新版本Code大于系统更新后的Code,则升级 return true; }else{ return false; } } /** * 设置今天已经检查过升级 * @return */ private void alreayCheckTodayUpdate(){ String date = sdf.format(new Date()); SharedPreferences sharedPreference = mContext.getSharedPreferences(SETTING_UPDATE_APK_INFO, 0); sharedPreference.edit().putString(CHECK_DATE, date).commit(); } }
3.UpdateAsyncTask.java
/** * 异步更新软件 * @author: aokunsang * @date: 2012-4-13 */ public class UpdateAsyncTask extends AsyncTask<Integer, Integer, String> { private final static String SETTING_UPDATE_APK_INFO = "setting_updateapkinfo"; private final static String UPDATE_DATE = "updatedate"; private final static String APK_VERSION = "apkversion"; private final static String APK_VERCODE = "apkvercode"; private final static String savePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + Const.apkSaveDir; private String fileName; private Context mContext; private ProgressBar progressView; //进度条 private TextView textView; private AlertDialog downloadDialog; //下载弹出框 private UpdateApkInfo apkInfo; //APK更新的详细信息 private boolean interceptFlag = false; //是否取消下载 private boolean sdExists = false; //是否存在SD卡 private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); public UpdateAsyncTask(Context mContext,UpdateApkInfo apkInfo) { this.mContext = mContext; this.apkInfo = apkInfo; if(apkInfo!=null){ fileName = savePath + "/" + apkInfo.getApkName(); } } /** * 升级成功,更新升级日期和版本号,和版本code */ private void alearyUpdateSuccess(){ SharedPreferences sharedPreference = mContext.getSharedPreferences(SETTING_UPDATE_APK_INFO, 0); sharedPreference.edit().putString(UPDATE_DATE, sdf.format(new Date())) .putString(APK_VERSION, apkInfo.getApkVersion()).putInt(APK_VERCODE, apkInfo.getAplVerCode()).commit(); } /** * 安装apk */ private void installApk(){ File file = new File(fileName); if(!file.exists()){ Log.i("---------软件更新之安装应用-------------", "找不到下载的软件"); return; } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); mContext.startActivity(intent); } /** * 检测手机是否存在SD卡 */ private boolean checkSoftStage(){ if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ //判断是否存在SD卡 File file = new File(savePath); if(!file.exists()){ file.mkdir(); } sdExists = true; return true; }else{ Toast.makeText(mContext, "检测到手机没有存储卡,请安装了内存卡后再升级。", Toast.LENGTH_LONG).show(); return false; } } @Override protected void onPreExecute() { if(apkInfo!=null && checkSoftStage()){ showDownloadDialog(); } super.onPreExecute(); } /** * 弹出下载进度对话框 */ private void showDownloadDialog(){ Builder builder = new AlertDialog.Builder(mContext); builder.setTitle("正在更新版本"); //---------------------------- 设置在对话框中显示进度条 --------------------------------------- final LayoutInflater inflater = LayoutInflater.from(mContext); View view = inflater.inflate(R.layout.updateprogressbar, 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(); } @Override protected String doInBackground(Integer... params) { String result = ""; if(apkInfo==null){ result = "fail"; }else if(!NetWorkAction.checkURL(apkInfo.getApkDownloadUrl())){ //检查apk的下载地址是否可用 result = "netfail"; }else if(apkInfo!=null && sdExists){ InputStream is = null; FileOutputStream fos = null; File file = new File(savePath); if(!file.exists()){ file.mkdirs(); } try { URL url = new URL(apkInfo.getApkDownloadUrl()); URLConnection urlConn = url.openConnection(); is = urlConn.getInputStream(); int length = urlConn.getContentLength(); //文件大小 fos = new FileOutputStream(fileName); int count = 0,numread = 0; byte buf[] = new byte[1024]; while(!interceptFlag && (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 onPostExecute(String result) { if(downloadDialog!=null){ downloadDialog.dismiss(); } if(!interceptFlag && "success".equals(result)){ alearyUpdateSuccess(); installApk(); }else if("netfail".equals(result)){ Toast.makeText(mContext, "连接服务器失败,请稍后重试。", Toast.LENGTH_LONG).show(); } super.onPostExecute(result); } @Override protected void onProgressUpdate(Integer... values) { int count = values[0]; progressView.setProgress(count); //设置下载进度 textView.setText("进度:"+count+"%"); super.onProgressUpdate(values); } }
4、UpdateReceiver.java
/** * 升级广播通知 * @author: aokunsang * @date: 2012-4-13 */ public class UpdateReceiver extends BroadcastReceiver { public final static String ACTION_PROCRESS = "com.peacemap.sl.jyg.intent.action.ACTION_PROCRESS"; public final static String PARAM_IN = "apkinfo"; @Override public void onReceive(Context context, Intent intent) { //获取升级APK的详细信息 UpdateApkInfo apkInfo = (UpdateApkInfo)intent.getExtras().getSerializable(PARAM_IN); //启动升级的异步进程 UpdateAsyncTask asyncTask = new UpdateAsyncTask(context,apkInfo); asyncTask.execute(10); } }
注意:UpdateReceiver需要在AndroidManifest.xml中配置:
<!-- 广播 --> <receiver android:name="com.peacemap.sl.jyg.receiver.UpdateReceiver" > <intent-filter> <!-- action的name值一定要和UpdateReceiver中的ACTION_PROCRESS一致 --> <action android:name="com.peacemap.sl.jyg.intent.action.ACTION_PROCRESS" /> </intent-filter> </receiver>
5.在下载的时候,有个下载进度对话框,需要一个XML或者用java代码写一个UI。
<?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>
6.其他实体类;
/** * 升级APK详细信息 * @author: aokunsang * @date: 2012-4-13 */ public class UpdateApkInfo implements Serializable { /** * */ private static final long serialVersionUID = 1L; private String apkVersion; //apk版本号 private String apkName; //apk名字 private String apkDownloadUrl; //下载地址 private int aplVerCode; //apk升级标示 setter和getter..... }
注:Const.java是final类型,属于常用数据存储类。放置一些URL路径的。
7、服务器类方法(读取配置文件内容)
/** * 检查apk是否可以升级 * {apkVersion:'1.10',apkVerCode:2,apkName:'1.1.apk',apkDownloadUrl:'http://localhost:8080/myapp/1.1.apk'} * @return */ @Action(value="checkUpdateApk") public String checkApkUpdate(){ Properties pp = new Properties(); ResourceLoader loader = new DefaultResourceLoader(); try { InputStream is = loader.getResource("classpath:config/sysconf.properties").getInputStream(); pp.load(new InputStreamReader(is, "utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } String apkVersion = pp.getProperty("apkVersion"); String apkDownloadUrl = pp.getProperty("apkDownloadUrl"); String apkName = pp.getProperty("apkName"); int apkVerCode = NumberUtils.toInt(pp.getProperty("apkVerCode"),0); String result = "{apkVersion:'"+apkVersion+"',apkVerCode:"+apkVerCode+",apkName:'"+apkName+"',apkDownloadUrl:'"+apkDownloadUrl+"'}"; Httptear.ResponseResultByEscape(result); //通过流写出去 // Httptear.ResponseResult(result); return NONE; }
评论
10 楼
king_tt
2014-05-30
youlingxifeng 写道
现在我自己做了一个,还行
求源码啊 。
9 楼
youlingxifeng
2014-05-26
现在我自己做了一个,还行
8 楼
king_tt
2014-04-16
468092550@qq.com 求源码啊。
7 楼
youlingxifeng
2012-12-26
可以把demo给我吗,xie774505257@163.com
6 楼
aokunsang
2012-12-18
xiasiming 写道
UpdateApkInfo跟Const这两个类是什么呢
这两个类我加上了,Const.java是个常量存储类。
ps:这是之前写的,里面用了广播和Service,可能有点乱用了。不过功能实现是没问题的,还有就是修“更新日志”没有显示。你借鉴参考即可。
5 楼
xiasiming
2012-12-17
UpdateApkInfo跟Const这两个类是什么呢
4 楼
xiasiming
2012-12-17
同上,建议楼主写个demo,实验了下 反省有几个类没有的,求个demo或工程,274898249@qq.com,这是邮箱啊 ,非常感谢
3 楼
zzyzyj
2012-09-14
能否发个源码,谢了!362931688@qq.com
2 楼
aokunsang
2012-09-10
yyj984551002 写道
能我整个工程发我不? 984551002@qq.com 先谢了!
这个我没有demo,做项目时候写的。基本所有有用代码就在上面了,你整合一下就可以使用了。
1 楼
yyj984551002
2012-09-07
能我整个工程发我不? 984551002@qq.com 先谢了!
发表评论
-
Android软件的自动更新【升级改革版】
2012-12-19 15:44 141051、之前写过一篇说版本升级的,用到广播。感觉乱用,搞的有 ... -
gridview图片展示,长按进入编辑模式
2012-08-31 14:53 14035看到小米手机和其他一些图片显示软件,gridview显示 ... -
Android-ExifInterface如何正确存取Double类型坐标
2012-08-10 15:08 48041、向图片中存储一些属性,可以使用ExifInter ... -
Android拍照,上传,预览综合【修改】
2011-12-07 14:21 33004最近需要做手机 ... -
百度地图的手动定位和自动定位
2011-07-07 18:45 52514最近由于项目需要,研究了下百度地图定位, ... -
android资源文件详细介绍
2011-07-01 13:45 3599摘自:http://blog.csdn.net/sayyanf ... -
谈Activity的生命周期
2011-07-01 13:42 1820摘自:http://blog.csdn.net/wyh0802 ... -
Android开发调试时logcat不显示问题
2011-07-01 13:40 2251摘自:http://dev.10086.cn/cmdn/wik ... -
AndroidManifest.xml详细介绍
2011-07-01 13:30 1841以下摘自网上,只为记录学习。 一、关于Andro ...
相关推荐
本文将深入探讨Android软件自动更新的相关知识点,包括实现机制、流程和注意事项。 一、Android自动更新原理 Android系统提供了多种自动更新方式,主要通过Google Play商店进行。当开发者发布新版本应用时,Play...
在Android开发中,实现软件自动更新是一...通过以上分析,我们可以了解到`android软件自动更新源码`涉及到的主要技术点和实现流程。在实际开发中,还需要根据项目需求和用户反馈不断优化更新机制,提供更好的用户体验。
在Android平台上,软件自动更新是一项重要的功能,它能让用户无需手动操作就能获取应用的最新版本。这个名为"UpdateDemo"的项目就是针对这一需求而设计的。下面将详细讲解实现Android APK自动更新的关键技术和步骤。...
在Android应用开发中,自动更新升级功能是必不可少的,它能确保用户始终使用最新、最稳定的应用版本。本文将深入探讨如何实现这一功能,并提供一个名为`UpdateSoftDemo`的示例项目,以便开发者直接应用到自己的项目...
在Android应用开发中,自动更新功能是提升用户体验和确保软件安全的重要组成部分。用户无需手动检查新版本,系统可自动检测并下载更新,简化了维护软件的流程。本篇将详细介绍如何在Android应用中实现自动更新功能,...
总的来说,实现Android软件自动更新是一个涉及网络请求、文件下载、权限管理和用户交互的过程。`UpdateService.java`是整个更新流程的核心部分,它将管理这些关键操作,确保应用能够顺利地进行版本更新。通过合理的...
Android软件自动更新的实现是一个重要的功能,它允许开发者轻松地向用户推送应用程序的最新版本,确保用户始终运行的是安全和优化的软件。在Android平台上,自动更新通常涉及到以下几个关键步骤和技术: 1. **...
"Android 应用软件自动更新源码"是一个示例项目,旨在教授如何在Android应用中实现自动更新的功能。以下是关于这个主题的详细知识点: 1. **自动更新机制**: - 自动更新通常通过网络请求检查服务器上的新版本信息...
调用方法 SoftUpdate softupdate = new SoftUpdate(this); softupdate.CheckSoftUpdate(false); 参数意思: 当前如果没有进程dialog的话,就用...当前如果有进程dialog的话,就用true,程序不会自动创建一个dialog
以上就是实现Android软件自动更新功能的基本步骤和关键点。这个功能不仅提高了用户体验,也确保了应用始终处于最新状态,减少了因旧版本导致的问题。在实际开发中,还需要考虑到错误处理、用户反馈以及网络连接变化...
### Android应用程序的自动更新升级 #### 一、引言 随着移动互联网的发展,应用程序更新成为提升用户体验、修复问题和引入新功能的重要手段。对于Android应用程序而言,具备版本检测和自动更新的功能不仅能够确保...
在"Android软件的自动更新【升级改革版】"中,可能涉及到以下关键知识点: 1. **网络请求库**:如Retrofit或OkHttp,用于向服务器发送HTTP请求,获取应用的版本信息和更新文件。 2. **文件下载管理**:如使用...
在Android平台上,实现应用的版本自动更新是一项重要的功能,它能确保用户始终使用到最新、最安全的软件版本。这个过程通常涉及到服务器端的更新管理、客户端的检测和下载以及安装流程。以下将详细讲解这一过程中的...
在Android开发中,实现应用的自动更新功能是提高用户体验、确保用户始终运行最新版本软件的重要手段。本篇文章将深入探讨如何构建一个Android自动更新程序,包括其背后的原理、实现步骤以及可能遇到的问题。 首先,...
Android软件自动更新升级(自动下载安装新版本)-附件资源
Android 实现软件自动更新的步骤 Android 实现软件自动更新是指在 Android 应用程序中实现自动更新功能,确保用户可以及时获取最新版本的应用程序。下面是实现 Android 软件自动更新的步骤: 1. 检查更新信息 在...
本篇文章将深入探讨Android软件的自动更新机制,特别是涉及静默更新以及需要Root权限的情况。 首先,自动更新是一种自动下载和安装应用新版本的过程,无需用户手动操作。Android Market(现为Google Play Store)...
在Android开发中,实现应用程序的自动更新功能是提高用户体验和保持软件安全性的重要一环。"Android 自动 更新 程序"是一个专为Android应用设计的自动更新解决方案,它允许应用在内网或外网环境下无缝地进行版本更新...