android更新软件,Android软件的自动更新

今天重新写了一篇自动更新的文章,参考:http://aokunsang.iteye.com/blog/1750440。本篇文章的源码整理了下,上传到了附件,需要的去下载。

看了几个博客,讲自动升级的程序,但是感觉都不是很完整,因为项目需要,自己手动写了个自动更新的程序,备忘下(本篇博客源码不上传了,免得误入歧途,需要源码的去新写的博客下载)。

一、 需求:如下图流程所示,需要在后台检查APK是否需要升级,需要升级则弹出提示下载升级对话框,用户点击下载进行升级,然后自动安装。

42699956_1.jpg

42699956_2.jpg

软件下载流程图:

42699956_3.jpg

二、 思路: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

Java代码 42699956_4.pngpublic 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

Java代码 42699956_4.png/**

* 检查是否有更新

* @author: aokunsang

* @date: 2012-4-13

*/

public class CheckUpdateAsyncTask extends AsyncTask {

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

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

Java代码 42699956_4.png/**

* 异步更新软件

* @author: aokunsang

* @date: 2012-4-13

*/

public class UpdateAsyncTask extends AsyncTask {

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

Java代码 42699956_4.png/**

* 升级广播通知

* @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中配置:

Xml代码 42699956_4.png

5.在下载的时候,有个下载进度对话框,需要一个XML或者用java代码写一个UI。

Xml代码 42699956_4.png<?xml  version="1.0" encoding="utf-8"?>

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

>

android:id="@+id/progressCount_text"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:textColor="@color/white"

android:textSize="14dip"

/>

android:id="@+id/progressbar"

style="?android:attr/progressBarStyleHorizontal"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

/>

6.其他实体类;

Java代码 42699956_4.png/**

* 升级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、服务器类方法(读取配置文件内容)

Java代码 42699956_4.png/**

* 检查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;

}

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值