看了几个博客,讲自动升级的程序,但是感觉都不是很完整,因为项目需要,自己手动写了个自动更新的程序,备忘下。
一、 需求:如下图流程所示,需要在后台检查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);
- receiver = new UpdateReceiver();
- registerReceiver(receiver, intentFilter);
-
- CheckUpdateAsyncTask checkAsyncTask = new CheckUpdateAsyncTask(WholeMainActivity.this);
- checkAsyncTask.execute(10);
- }
- }
2、CheckUpdateAsyncTask.java
-
-
-
-
-
- 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() {
-
- 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);
- 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();
- }
-
-
-
-
-
- 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();
- }
- }
-
-
-
-
- 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 {
-
- 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;
- }
-
-
-
-
- private boolean checkApkVersion(){
- SharedPreferences sharedPreference = mContext.getSharedPreferences(SETTING_UPDATE_APK_INFO, 0);
- int verCode = sharedPreference.getInt(APK_VERCODE, 0);
- if(apkInfo.getAplVerCode()>verCode){
- return true;
- }else{
- return false;
- }
- }
-
-
-
-
- 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
-
-
-
-
-
- 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;
-
- private boolean interceptFlag = false;
- private boolean sdExists = false;
-
- 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();
- }
- }
-
-
-
-
- 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();
- }
-
-
-
-
- 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);
- }
-
-
-
- private boolean checkSoftStage(){
- if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
- 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())){
- 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
-
-
-
-
-
- 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) {
-
- 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 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>