Android app更新模块

转自:http://blog.csdn.net/donotwarry/article/details/6931307

前不久接到个任务,在我们的app里面添加更新模块,在之前的版本中,我们的更新都是直接通过浏览器下载apk包来安装更新的,我想各位很大一部分应用的更新方法都是这样,因为它简单、方便,但是他也有许多不好的地方,比如需要用户跳转到浏览器页面、下载不可控、网络不好的情况的下失败无法续传,退出浏览器就无法接着下了等。。


     于是我们这个更新模块的需求就来了

1.下载后台进行,退出我们应用下载任务依旧能继续执行操作

2.下载文件支持断点续传

3.下载任务支持没有安装sdcard时也可下载更新

4.notify栏提示操作


   对几个需求稍作分析,解决方法如下:

1.下载更新的线程放到一个service中去,service的好处是不易被系统回收,而且也容易操作。我们需要先在AndroidMainfest.xml文件中去注册这个service

[html]   view plain copy
  1. <service android:name="com.dj.app.UpdateService"/>  

2.断点续传,请求头中有个重要的参数range,代表的意思的我要取的数据的范围,这个需要服务器支持,默认情况都是支持的。我的思路是下载前先获取文件包大小,然后检查是否已经有下载好的部分了,没有就从头开始,有就接着下。

[java]   view plain copy
  1. request.addHeader("Range""bytes=" + downLength + "-");  

为了支持断点续传,我将下载好的文件版本号、文件长度都以prefrence的形似保存下来,下次更新如果还是这个版本就接着下,如果又有更新的了就删掉重下。

[java]   view plain copy
  1. private void checkTemFile() {  
  2.             existTemFileVersionCode = preferences().getInt(  
  3.                     UPDATE_FILE_VERSIONCODE, 0);  
  4.             if (newestVersionCode == existTemFileVersionCode  
  5.                     || newestVersionCode == TEST) {  
  6.                 File temFile = new File(context.getFilesDir(),  
  7.                         Integer.valueOf(newestVersionCode) + ".apk");  
  8.                 if (!temFile.exists()) {  
  9.                     saveLogFile(newestVersionCode, 0);  
  10.                 }  
  11.             } else {  
  12.                 deleteApkFile(existTemFileVersionCode);  
  13.                 saveLogFile(newestVersionCode, 0);  
  14.             }  
  15. }  


3.无sdcard时也能下载,那只能将apk包下载到系统内存中

[java]   view plain copy
  1. context.getFilesDir();  
这样创建的文件在/data/data/应用包名/files

伪代码:

[java]   view plain copy
  1. if (downLength > 0) {//接着上次的下载  
  2.   
  3.     outStream = context.openFileOutput(Integer.valueOf(newestVersionCode) + ".apk",  
  4.             Context.MODE_APPEND+ Context.MODE_WORLD_READABLE);  
  5.   
  6. else {//从头开始下载  
  7.       outStream = context.openFileOutput(Integer.valueOf(newestVersionCode) + ".apk",Context.MODE_WORLD_READABLE);  
  8. }  


4.notify,我设定了一个更新notify的线程专门去观察下载线程的进度,每一分钟更新一次notify中的进度条。

[java]   view plain copy
  1. new Thread() {  
  2.                 public void run() {  
  3.                     try {  
  4.                         boolean notFinish = true;  
  5.                         while (notFinish) {  
  6.                             Thread.sleep(1000);  
  7.                             notFinish = false;  
  8.                             if (downloadThread == null) {  
  9.                                 break;  
  10.                             }  
  11.                             if (!downloadThread.downFinish) {  
  12.                                 notFinish = true;  
  13.                             }  
  14.                             downloadThread.showNotification();  
  15.                         }  
  16.                     } catch (Exception e) {  
  17.                         e.printStackTrace();  
  18.                     } finally {  
  19.                         stopSelf();  
  20.                     }  
  21.                 };  
  22.             }.start();  

downloadThread就是我的下载线程了因为要对不同进度时有不同的控制,这个可以通过notification.contentIntent来进行设定,比如100%的时候,我想要用户点击通知栏,即可进行安装,则应该这样做

[java]   view plain copy
  1. notification.tickerText = "下载完成";  
  2.                     notification.when = System.currentTimeMillis();  
  3.                     Intent notificationIntent = new Intent();  
  4.                     notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  5.                     notificationIntent  
  6.                             .setAction(android.content.Intent.ACTION_VIEW);  
  7.                     String type = "application/vnd.android.package-archive";  
  8.                     notificationIntent.setDataAndType(  
  9.                             Uri.parse("file:///data/data/"  
  10.                                     + context.getPackageName()  
  11.                                     + "/files/"  
  12.                                     + (Integer.valueOf(newestVersionCode)  
  13.                                             .toString()) + ".apk"), type);  
  14.                     notification.contentView = rv;  
  15.                     notification.flags = Notification.FLAG_AUTO_CANCEL;  
  16.                     notification.contentView  
  17.                             .setProgressBar(  
  18.                                     R.id.update_notification_progressbar, 100,  
  19.                                     p, false);  
  20.                     notification.contentView.setTextViewText(  
  21.                             R.id.update_notification_progresstext, p + "%");  
  22.                     notification.contentView.setTextViewText(  
  23.                             R.id.update_notification_title, "下载完成,点击安装");  
  24.                     PendingIntent contentIntent = PendingIntent.getActivity(  
  25.                             context, 0, notificationIntent, 0);  
  26.                     notification.contentIntent = contentIntent;  


 

 

下面我将下载线程完整的代码贴出来

[java]   view plain copy
  1. class DownloadThread extends Thread {  
  2.     private static final String UPDATE_FILE_VERSIONCODE = "updateTemFileVersionCode";  
  3.     private static final String UPDATE_FILE_LENGTH = "updateTemFileLength";  
  4.     private static final String TEST_UPDATE_FILE_LENGTH = "testupdatefilelength";  
  5.     private static final int BUFFER_SIZE = 1024;  
  6.     private static final int NETWORK_CONNECTION_TIMEOUT = 15000;  
  7.     private static final int NETWORK_SO_TIMEOUT = 15000;  
  8.     private int newestVersionCode, existTemFileVersionCode;  
  9.     private String downUrl;  
  10.     private int fileLength = Integer.MAX_VALUE;  
  11.     private int downLength;  
  12.     private boolean downFinish;  
  13.   
  14.     private static final int CHECK_FAILED = -1;  
  15.     private static final int CHECK_SUCCESS = 0;  
  16.     private static final int CHECK_RUNNING = 1;  
  17.     private int checkStatus;  
  18.     private boolean isChecking = false;  
  19.   
  20.     private Context context;  
  21.     private boolean isPercentZeroRunning = false;  
  22.     private boolean stop;  
  23.     private Object block = new Object();  
  24.     private boolean receiverRegistered = false;  
  25.   
  26.     private NotificationManager mNM;  
  27.     private RemoteViews rv;  
  28.   
  29.     public DownloadThread(Context context, String downUrl, int versionCode) {  
  30.         super("DownloadThread");  
  31.         this.downUrl = downUrl;  
  32.         this.newestVersionCode = versionCode;  
  33.         this.context = context;  
  34.         this.mNM = (NotificationManager) context  
  35.                 .getSystemService(Context.NOTIFICATION_SERVICE);  
  36.         this.rv = new RemoteViews(context.getPackageName(), R.layout.notify);  
  37.         this.downFinish = false;  
  38.     }  
  39.   
  40.     private void checkTemFile() {  
  41.         existTemFileVersionCode = preferences().getInt(  
  42.                 UPDATE_FILE_VERSIONCODE, 0);  
  43.         if (newestVersionCode == existTemFileVersionCode  
  44.                 || newestVersionCode == TEST) {  
  45.             File temFile = new File(context.getFilesDir(),  
  46.                     Integer.valueOf(newestVersionCode) + ".apk");  
  47.             if (!temFile.exists()) {  
  48.                 saveLogFile(newestVersionCode, 0);  
  49.             }  
  50.         } else {  
  51.             deleteApkFile(existTemFileVersionCode);  
  52.             saveLogFile(newestVersionCode, 0);  
  53.         }  
  54.     }  
  55.   
  56.     private void deleteApkFile(int existVersionCode) {  
  57.         File temFile = new File(context.getFilesDir(),  
  58.                 Integer.valueOf(existVersionCode) + ".apk");  
  59.         if (temFile.exists()) {  
  60.             temFile.delete();  
  61.         }  
  62.     }  
  63.   
  64.     private SharedPreferences preferences() {  
  65.         return context.getSharedPreferences(context.getPackageName(),  
  66.                 Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);  
  67.     }  
  68.   
  69.     private void saveLogFile(int versionCode, int downloadLength) {  
  70.         SharedPreferences.Editor edit = preferences().edit();  
  71.         if (versionCode == TEST) {  
  72.             edit.putInt(TEST_UPDATE_FILE_LENGTH, downloadLength);  
  73.         } else {  
  74.             edit.putInt(UPDATE_FILE_VERSIONCODE, versionCode);  
  75.             edit.putInt(UPDATE_FILE_LENGTH, downloadLength);  
  76.         }  
  77.         edit.commit();  
  78.     }  
  79.   
  80.     @Override  
  81.     public void run() {  
  82.         checkTemFile();  
  83.         this.stop = false;  
  84.         while (!downFinish) {  
  85.             Log.i(TAG, "download thread start : while()");  
  86.             if (newestVersionCode == TEST) {  
  87.                 downLength = preferences().getInt(TEST_UPDATE_FILE_LENGTH,  
  88.                         0);  
  89.             } else {  
  90.                 downLength = preferences().getInt(UPDATE_FILE_LENGTH, 0);  
  91.             }  
  92.   
  93.             InputStream is = null;  
  94.             FileOutputStream outStream = null;  
  95.             try {  
  96.                 // check the network  
  97.                 ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);  
  98.                 NetworkInfo ni = cm.getActiveNetworkInfo();  
  99.                 boolean con = ni == null ? false : ni  
  100.                         .isConnectedOrConnecting();  
  101.                 synchronized (block) {  
  102.                     if (!con) {  
  103.                         context.registerReceiver(  
  104.                                 receiver,  
  105.                                 new IntentFilter(  
  106.                                         ConnectivityManager.CONNECTIVITY_ACTION));  
  107.                         receiverRegistered = true;  
  108.                         try {  
  109.                             Log.i(TAG, "network is not ok : block.wait()");  
  110.                             block.wait();  
  111.                         } catch (InterruptedException e1) {  
  112.                         }  
  113.                     }  
  114.                 }  
  115.   
  116.                 if (fileLength == Integer.MAX_VALUE) {  
  117.                     URL url = new URL(downUrl);  
  118.                     HttpURLConnection conn = (HttpURLConnection) url  
  119.                             .openConnection();  
  120.                     if (conn.getResponseCode() / 100 == 2  
  121.                             && conn.getContentLength() != -1) {  
  122.                         fileLength = conn.getContentLength();  
  123.                         Log.i(TAG, "getContentLength == " + fileLength);  
  124.                     } else {  
  125.                         Thread.sleep(5000);  
  126.                         Log.i(TAG, "getContentLength failed : retry in 5 second later");  
  127.                         continue;  
  128.                     }  
  129.                 }  
  130.   
  131.                 HttpClient httpClient = new DefaultHttpClient();  
  132.                 HttpGet request = new HttpGet(downUrl);  
  133.                 request.addHeader("Range""bytes=" + downLength + "-");  
  134.   
  135.                 if (downLength < fileLength) {  
  136.                     HttpHost proxy = HttpBase.globalProxy();  
  137.                     HttpParams httpParams = request.getParams();  
  138.                     HttpConnectionParams.setConnectionTimeout(httpParams,  
  139.                             NETWORK_CONNECTION_TIMEOUT);  
  140.                     HttpConnectionParams.setSoTimeout(httpParams,  
  141.                             NETWORK_SO_TIMEOUT);  
  142.                     ConnRouteParams.setDefaultProxy(request.getParams(),  
  143.                             proxy);  
  144.   
  145.                     HttpResponse response = httpClient.execute(request);  
  146.                     Log.i(TAG, "getContent's response status == "  
  147.                             + response.getStatusLine().getStatusCode());  
  148.                     if (response.getStatusLine().getStatusCode() / 100 != 2) {  
  149.                         continue;  
  150.                     }  
  151.                     HttpEntity entity = response.getEntity();  
  152.                     is = entity.getContent();  
  153.                     byte[] buffer = new byte[BUFFER_SIZE];  
  154.                     int offset = 0;  
  155.   
  156.                     if (downLength > 0) {  
  157.                         outStream = context  
  158.                                 .openFileOutput(  
  159.                                         Integer.valueOf(newestVersionCode)  
  160.                                                 + ".apk",  
  161.                                         Context.MODE_APPEND  
  162.                                                 + Context.MODE_WORLD_READABLE);  
  163.   
  164.                     } else {  
  165.                         outStream = context  
  166.                                 .openFileOutput(  
  167.                                         Integer.valueOf(newestVersionCode)  
  168.                                                 + ".apk",  
  169.                                         Context.MODE_WORLD_READABLE);  
  170.                     }  
  171.   
  172.                     while ((offset = is.read(buffer, 0, BUFFER_SIZE)) != -1  
  173.                             && !stop) {  
  174.                         outStream.write(buffer, 0, offset);  
  175.                         downLength += offset;  
  176.                     }  
  177.                 }  
  178.                 if (downLength == fileLength) {  
  179.                     File apkFile = new File(context.getFilesDir(),  
  180.                             Integer.valueOf(newestVersionCode) + ".apk");  
  181.                     if (isApkFileOK(apkFile)) {  
  182.                         checkStatus = CHECK_SUCCESS;  
  183.                     } else {  
  184.                         deleteApkFile(newestVersionCode);  
  185.                         saveLogFile(existTemFileVersionCode, 0);  
  186.                         checkStatus = CHECK_FAILED;  
  187.                     }  
  188.                     this.downFinish = true;  
  189.                 }  
  190.   
  191.             } catch (Exception e) {  
  192.             } finally {  
  193.                 saveLogFile(newestVersionCode, downLength);  
  194.                 if (receiverRegistered) {  
  195.                     context.unregisterReceiver(receiver);  
  196.                     receiverRegistered = false;  
  197.                 }  
  198.   
  199.                 if (stop || downFinish) {  
  200.                     break;  
  201.                 }  
  202.                 try {  
  203.                     if (outStream != null) {  
  204.                         outStream.close();  
  205.                     }  
  206.                     if (is != null) {  
  207.                         is.close();  
  208.                     }  
  209.                 } catch (IOException e) {  
  210.                 }  
  211.             }  
  212.         }  
  213.   
  214.     }  
  215.   
  216.     @Override  
  217.     public void interrupt() {  
  218.         synchronized (block) {  
  219.             Log.i(TAG, "block.notify()");  
  220.             block.notify();  
  221.         }  
  222.     }  
  223.   
  224.     private void cancel() {  
  225.         stop = true;  
  226.         mNM.cancel(MOOD_NOTIFICATIONS);  
  227.     }  
  228.   
  229.     private boolean isApkFileOK(File file) {  
  230.         checkStatus = CHECK_RUNNING;  
  231.         // first check the file header  
  232.         /*if (file.isDirectory() || !file.canRead() || file.length() < 4) { 
  233.             return false; 
  234.         } 
  235.         DataInputStream in = null; 
  236.         try { 
  237.             in = new DataInputStream(new BufferedInputStream( 
  238.                     new FileInputStream(file))); 
  239.             int test = in.readInt(); 
  240.             if (test != 0x504b0304) 
  241.                 return false; 
  242.         } catch (IOException e) { 
  243.             return false; 
  244.         } finally { 
  245.             try { 
  246.                 in.close(); 
  247.             } catch (IOException e) { 
  248.             } 
  249.         }*/  
  250.   
  251.         // second unZip file to check(without saving)  
  252.         boolean result = unzip(file);  
  253.         isChecking = false;  
  254.         return result;  
  255.     }  
  256.   
  257.     private boolean unzip(File unZipFile) {  
  258.         boolean succeed = true;  
  259.         ZipInputStream zin = null;  
  260.         ZipEntry entry = null;  
  261.         try {  
  262.             zin = new ZipInputStream(new FileInputStream(unZipFile));  
  263.             boolean first = true;  
  264.             while (true) {  
  265.                 if ((entry = zin.getNextEntry()) == null) {  
  266.                     if (first)  
  267.                         succeed = false;  
  268.                     break;  
  269.                 }  
  270.                 first = false;  
  271.                 if (entry.isDirectory()) {  
  272.                     zin.closeEntry();  
  273.                     continue;  
  274.                 }  
  275.                 if (!entry.isDirectory()) {  
  276.                     byte[] b = new byte[1024];  
  277.                     @SuppressWarnings("unused")  
  278.                     int len = 0;  
  279.                     while ((len = zin.read(b)) != -1) {  
  280.                     }  
  281.                     zin.closeEntry();  
  282.                 }  
  283.             }  
  284.         } catch (IOException e) {  
  285.             succeed = false;  
  286.         } finally {  
  287.             if (null != zin) {  
  288.                 try {  
  289.                     zin.close();  
  290.                 } catch (IOException e) {  
  291.                 }  
  292.             }  
  293.         }  
  294.         return succeed;  
  295.     }  
  296.   
  297.     public void showNotification() {  
  298.         float result = (float) downLength / (float) fileLength;  
  299.         int p = (int) (result * 100);  
  300.         if (p == 0 && isPercentZeroRunning || p == 100 && isChecking) {  
  301.             return;  
  302.         } else if (p != 0) {  
  303.             isPercentZeroRunning = false;  
  304.         }  
  305.         Notification notification = new Notification(R.drawable.icon, null,  
  306.                 0);  
  307.   
  308.         if (p == 100) {  
  309.             if (checkStatus == CHECK_RUNNING) {  
  310.                 notification.tickerText = "开始检查下载文件";  
  311.                 notification.when = System.currentTimeMillis();  
  312.                 notification.flags = notification.flags  
  313.                         | Notification.FLAG_ONGOING_EVENT  
  314.                         | Notification.FLAG_NO_CLEAR;  
  315.                 notification.contentView = rv;  
  316.                 notification.contentView.setProgressBar(  
  317.                         R.id.update_notification_progressbar, 100, p, true);  
  318.                 notification.contentView.setTextViewText(  
  319.                         R.id.update_notification_title, "正在检查下载文件...");  
  320.                 PendingIntent contentIntent = PendingIntent.getActivity(  
  321.                         context, 0null0);  
  322.                 notification.contentIntent = contentIntent;  
  323.                 isChecking = true;  
  324.             } else if (checkStatus == CHECK_FAILED) {  
  325.                 notification.tickerText = "文件验证失败!";  
  326.                 notification.when = System.currentTimeMillis();  
  327.                 notification.flags = notification.flags  
  328.                         | Notification.FLAG_AUTO_CANCEL;  
  329.                 notification.contentView = rv;  
  330.                 notification.contentView.setProgressBar(  
  331.                         R.id.update_notification_progressbar, 100, p, false);  
  332.                 notification.contentView.setTextViewText(  
  333.                         R.id.update_notification_title, "文件验证失败,请重新下载");  
  334.                 Intent notificationIntent = new Intent(context,  
  335.                         UpdateService.class);  
  336.                 notificationIntent.setAction(ACTION_STOP);  
  337.                 PendingIntent contentIntent = PendingIntent.getService(  
  338.                         context, 0, notificationIntent, 0);  
  339.                 notification.contentIntent = contentIntent;  
  340.             } else {  
  341.                 notification.tickerText = "下载完成";  
  342.                 notification.when = System.currentTimeMillis();  
  343.                 Intent notificationIntent = new Intent();  
  344.                 notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  345.                 notificationIntent  
  346.                         .setAction(android.content.Intent.ACTION_VIEW);  
  347.                 String type = "application/vnd.android.package-archive";  
  348.                 notificationIntent.setDataAndType(  
  349.                         Uri.parse("file:///data/data/"  
  350.                                 + context.getPackageName()  
  351.                                 + "/files/"  
  352.                                 + (Integer.valueOf(newestVersionCode)  
  353.                                         .toString()) + ".apk"), type);  
  354.                 notification.contentView = rv;  
  355.                 notification.flags = Notification.FLAG_AUTO_CANCEL;  
  356.                 notification.contentView  
  357.                         .setProgressBar(  
  358.                                 R.id.update_notification_progressbar, 100,  
  359.                                 p, false);  
  360.                 notification.contentView.setTextViewText(  
  361.                         R.id.update_notification_progresstext, p + "%");  
  362.                 notification.contentView.setTextViewText(  
  363.                         R.id.update_notification_title, "下载完成,点击安装");  
  364.                 PendingIntent contentIntent = PendingIntent.getActivity(  
  365.                         context, 0, notificationIntent, 0);  
  366.                 notification.contentIntent = contentIntent;  
  367.             }  
  368.   
  369.         } else if (p == 0) {  
  370.             notification.tickerText = "准备下载";  
  371.             notification.when = System.currentTimeMillis();  
  372.             Intent notificationIntent = new Intent(context,  
  373.                     UpdateService.class);  
  374.             notificationIntent.setAction(ACTION_STOP);  
  375.             notification.flags = notification.flags  
  376.                     | Notification.FLAG_ONGOING_EVENT;  
  377.             notification.contentView = rv;  
  378.             notification.contentView.setProgressBar(  
  379.                     R.id.update_notification_progressbar, 100, p, true);  
  380.             notification.contentView.setTextViewText(  
  381.                     R.id.update_notification_title, "正在准备下载(点击取消)");  
  382.             PendingIntent contentIntent = PendingIntent.getService(context,  
  383.                     0, notificationIntent, 0);  
  384.             notification.contentIntent = contentIntent;  
  385.             isPercentZeroRunning = true;  
  386.         } else {  
  387.             notification.tickerText = "开始下载";  
  388.             notification.when = System.currentTimeMillis();  
  389.             Intent notificationIntent = new Intent(context,  
  390.                     UpdateService.class);  
  391.             notificationIntent.setAction(ACTION_STOP);  
  392.             notification.contentView = rv;  
  393.             notification.flags = notification.flags  
  394.                     | Notification.FLAG_ONGOING_EVENT;  
  395.             notification.contentView.setProgressBar(  
  396.                     R.id.update_notification_progressbar, 100, p, false);  
  397.             notification.contentView.setTextViewText(  
  398.                     R.id.update_notification_progresstext, p + "%");  
  399.             notification.contentView.setTextViewText(  
  400.                     R.id.update_notification_title, "正在下载(点击取消)");  
  401.             PendingIntent contentIntent = PendingIntent.getService(context,  
  402.                     0, notificationIntent, 0);  
  403.             notification.contentIntent = contentIntent;  
  404.         }  
  405.   
  406.         mNM.notify(MOOD_NOTIFICATIONS, notification);  
  407.     }  
  408. }  

可以看到,我的下载是包裹在一个while循环中的,假如没有下载完成,我会一直重复这个循环,可以注意到,我在取数据的时候有个标志位stop

[java]   view plain copy
  1. while ((offset = is.read(buffer, 0, BUFFER_SIZE)) != -1  
  2.                                 && !stop) {  
  3.                             outStream.write(buffer, 0, offset);  
  4.                             downLength += offset;  
  5.                         }  
 
有了这个就可以在外面控制强制停止下载。 

在下载开始阶段我最先做的时就是检查网络情况,如果没有网络,我就使用一个block让这个线程阻塞掉,有人会问那什么时候恢复呢?我在service里面加了个广播

[java]   view plain copy
  1. private final BroadcastReceiver receiver = new BroadcastReceiver() {  
  2.   
  3.         @Override  
  4.         public void onReceive(Context context, Intent intent) {  
  5.             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent  
  6.                     .getAction())) {  
  7.                 NetworkInfo info = (NetworkInfo) intent  
  8.                         .getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);  
  9.                 boolean hasConnectivity = (info != null && info.isConnected()) ? true  
  10.                         : false;  
  11.                 if (hasConnectivity && downloadThread != null) {  
  12.                     downloadThread.interrupt();  
  13.                 }  
  14.             }  
  15.         }  
  16.   
  17. };  

可以监听系统网络情况,如果连上了,就调用interrupt()来唤醒线程。这样做的好处时,在没有网络时,这个线程不会无限循环的去获取数据。


最后在这个版本发布后因为代码一些bug导致,如果网络数据获取有问题,则用户下载下来的安装包就会解析错误,而且这是个死胡同,除非去手动下载个好的安装包来装,否则我们软件会一直提示,一直完成,但是一直装不上。。。哎,我们用户可是百万级啊,这个bug很致命,还好当时做了备用方案,可以由服务器控制客户端更新方法,于是改为以前的更新。


这也是我在上面的代码中下载完成时加入了最后一步,校验安装包的过程。我们都知道apk就是一个zip文件,通常对一个zip文件的校验,最简单的是校验文件头是不是0x504b0304,但是这只是文件格式的判断,加入是文件内容字节损坏还是查不出来,只能通过去unzip这个文件来捕获异常。在上面unzip(File unZipFile)方法中,我尝试去解压软件,对ZipInputStream流我没做任何处理,仅仅是看这个解压过程是否正常,以此判断这个zip文件是否正常,暂时也没想到更好的办法。

[java]   view plain copy
  1. private boolean unzip(File unZipFile) {  
  2.     boolean succeed = true;  
  3.     ZipInputStream zin = null;  
  4.     ZipEntry entry = null;  
  5.     try {  
  6.         zin = new ZipInputStream(new FileInputStream(unZipFile));  
  7.         boolean first = true;  
  8.         while (true) {  
  9.             if ((entry = zin.getNextEntry()) == null) {  
  10.                 if (first)  
  11.                     succeed = false;  
  12.                 break;  
  13.             }  
  14.             first = false;  
  15.             if (entry.isDirectory()) {  
  16.                 zin.closeEntry();  
  17.                 continue;  
  18.             }  
  19.             if (!entry.isDirectory()) {  
  20.                 byte[] b = new byte[1024];  
  21.                 @SuppressWarnings("unused")  
  22.                 int len = 0;  
  23.                 while ((len = zin.read(b)) != -1) {  
  24.                 }  
  25.                 zin.closeEntry();  
  26.             }  
  27.         }  
  28.     } catch (IOException e) {  
  29.         succeed = false;  
  30.     } finally {  
  31.         if (null != zin) {  
  32.             try {  
  33.                 zin.close();  
  34.             } catch (IOException e) {  
  35.             }  
  36.         }  
  37.     }  
  38.     return succeed;  
  39. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值