Android 实现从后台下载apk文件,保存到本地sd卡,使用系统安装apk,完成版本更新功能

LoadAppUtil.java

  1 import java.io.File;
  2 import java.io.FileOutputStream;
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.net.HttpURLConnection;
  6 import java.net.URL;
  7 import java.util.ArrayList;
  8 import java.util.List;
  9 
 10 /**
 11  * Depiction:
 12  * Author: kuzan
 13  * Date: 2017/01/14 9:42
 14  */
 15 public class LoadAppUtil {
 16 
 17     private static List<String> list = new ArrayList<>();
 18     private static final int TIMEOUT = 10 * 60 * 1000; // 超时
 19 
 20     public static final int LOAD_PROCESS = 1;
 21     public static final int LOAD_SUCCEED = 2;
 22     public static final int LOAD_ERROR = 3;
 23 
 24     /**
 25      * 下载apk
 26      * @param context
 27      * @param packageName 保存apk的名称
 28      * @param url apk后台下载的地址
 29      */
 30     public static void loadApp(Context context, final String packageName, final String url) {
 31 
 32         final String path = getLoadAppPath(context, packageName);
 33 
 34         if (StringUtils.isEmptyString(path) || StringUtils.isEmptyString(url)) {
 35             loadError(packageName);
 36             return;
 37         }
 38 
 39         // 判断是否在下载
 40         if (list.contains(packageName)) {
 41             return;
 42         }
 43 
 44         list.add(packageName);
 45 
 46         new Thread(new Runnable() {
 47             @Override
 48             public void run() {
 49                 downloadUpdateFile(packageName, url, path);
 50             }
 51         }).start();
 52     }
 53 
 54     /**
 55      * 文件下载
 56      * @param packageName 保存apk的名称
 57      * @param down_url apk后台下载的地址
 58      * @param file 保存apk的文件路径
 59      * */
 60     public static void downloadUpdateFile(String packageName, String down_url, String file) {
 61 
 62         int totalSize = 0; // 文件总大小
 63         InputStream in = null;
 64         FileOutputStream fos = null;
 65 
 66         FileUtils.deleteFile(file);
 67         FileUtils.createFile(file);
 68 
 69         URL url;
 70         try {
 71             url = new URL(down_url);
 72 
 73             HttpURLConnection httpURLConnection = (HttpURLConnection) url
 74                     .openConnection();
 75 
 76             httpURLConnection.setConnectTimeout(TIMEOUT);
 77 
 78             httpURLConnection.setReadTimeout(TIMEOUT);
 79 
 80             // 获取下载文件的size
 81             totalSize = httpURLConnection.getContentLength();
 82             Log.e("LoadAppUtil", "totalSize = " + totalSize);
 83 
 84             if (httpURLConnection.getResponseCode() == 404) {
 85                 loadError(packageName);
 86                 return;
 87             }
 88 
 89             in = httpURLConnection.getInputStream();
 90             fos = new FileOutputStream(file, false);
 91         } catch (IOException e) {
 92             e.printStackTrace();
 93             loadError(packageName);
 94             return;
 95         }
 96 
 97         int downloadCount = 0; // 已下载大小
 98         int updateProgress = 0; // 更新进度
 99 
100         byte buffer[] = new byte[64];
101         int readsize = 0;
102 
103         try {
104             LoadBean bean = new LoadBean(packageName,file,0);
105             post(LOAD_PROCESS,bean);
106             while ((readsize = in.read(buffer)) != -1) {
107 
108                 fos.write(buffer, 0, readsize);
109 
110                 // 计算已下载到的大小
111                 downloadCount += readsize;
112 
113                 // 先计算已下载的百分比,然后跟上次比较是否有增加,有则更新通知进度
114                 int now = downloadCount * 100 / totalSize;
115                 // Log.e(TAG, "now = " + now) ;
116                 if (updateProgress < now) {
117                     updateProgress = now;
118                     // 发送下载进度
119                     bean.setProcess(now);
120                     post(LOAD_PROCESS,bean);
121                 }
122             }
123         } catch (Exception e) {
124             e.printStackTrace();
125             loadError(packageName);
126             return;
127         } finally {
128             try {
129                 fos.close();
130                 in.close();
131             } catch (IOException e) {
132                 e.printStackTrace();
133             }
134         }
135 
136         // 发送下载完成消息
137         if(list.contains(packageName)){
138             list.remove(packageName);
139             LoadBean bean = new LoadBean(packageName,file,100);
140             post(LOAD_SUCCEED,bean);
141         }
142 
143     }
144 
145     private static void loadError(String packageName) {
146         if (list.contains(packageName)) {
147             list.remove(packageName);
148         }
149         // 发送下载错误消息
150         LoadBean bean = new LoadBean(packageName,"",0);
151         post(LOAD_ERROR,bean);
152     }
153 
154     /**
155      * 获取保存apk的文件路径
156      *
157      * @param context
158      * @return
159      */
160     public static String getLoadAppPath(Context context, String packageName) {
161         if (FileUtils.isSdCardExist()) {
162             return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + File.separator + packageName + ".apk";
163         }
164         return "";
165     }
166 
167     /**
168      * 判断文件是否存在
169      * @param path 文件路径
170      * @return
171      */
172     public static boolean isFileExists(String path) {
173         if (TextUtils.isEmpty(path)) {
174             return false;
175         }
176         try {
177             File f=new File(path);
178             if(!f.exists()) {
179                 return false;
180             }
181         }
182         catch (Exception e) {
183             return false;
184         }
185 
186         return true;
187     }
188 
189     /**
190      * 通知UI
191      * */
192     public static void post(int clickId,LoadBean bean){
193         RxBus.getDefault().post(RxBusEvent.newBuilder(R.id.load_apk).clickId(clickId).setObj(bean).build());
194     }
195 }

调用方法:

LoadAppUtil.loadApp(UpdateActivity.this, newVersionName, UrlConstants.UPLOAD_URL);

信息读取:(使用的消息通知是android RxBus)

 1 mySubscriptions.add(RxBus.getDefault().toObserverable(RxBusEvent.class).subscribe(new Action1<RxBusEvent>() {
 2             @Override
 3             public void call(final RxBusEvent rxBusEvent) {
 4                 if (rxBusEvent.getType() == R.id.load_apk) {
 5                     switch (rxBusEvent.getClickId()) {
 6                         case LoadAppUtil.LOAD_SUCCEED:
 7                             runOnUiThread(new Runnable() {
 8                                 @Override
 9                                 public void run() {
10                                     // 下载完成
11                                     Log.e("LOAD", "LOAD_SUCCEED");
12                                     AppUtils.installApp(UpdateActivity.this, (LoadBean) rxBusEvent.getObj().getPath());
13                                     isLoadFinish = true;
14                                 }
15                             });
16                             break;
17 
18                         case LoadAppUtil.LOAD_PROCESS:
19                             runOnUiThread(new Runnable() {
20                                 @Override
21                                 public void run() {
22                                     // 下载进度
23                                     isLoadFinish = false;
24                                     updateProgress((LoadBean) rxBusEvent.getObj());
25                                 }
26                             });
27                             break;
28 
29                         case LoadAppUtil.LOAD_ERROR:
30                             runOnUiThread(new Runnable() {
31                                 @Override
32                                 public void run() {
33                                     // 下载出错
34                                     Log.e("upload", "err");
35                                     isLoadFinish = false;
36                                     ToastUtils.ToastMessage(UpdateActivity.this, "下载失败");
37                                 }
38                             });
39                             break;
40                     }
41                 }
42             }
43         }));

LoadBean.java

 1 public class LoadBean {
 2 
 3     private String packageName;
 4     private String path;
 5     private int process;
 6 
 7     public LoadBean(String packageName, String path, int process) {
 8         this.packageName = packageName;
 9         this.path = path;
10         this.process = process;
11     }
12 
13     public String getPackageName() {
14         return packageName;
15     }
16 
17     public void setPackageName(String packageName) {
18         this.packageName = packageName;
19     }
20 
21     public String getPath() {
22         return path;
23     }
24 
25     public void setPath(String path) {
26         this.path = path;
27     }
28 
29     public int getProcess() {
30         return process;
31     }
32 
33     public void setProcess(int process) {
34         this.process = process;
35     }
36 }