Android App自動更新解決方案(DownloadManager)


 

 

一開始,我們先向服務器請求數據獲取版本

 1    public ObservableField<VersionBean> appVersion = new ObservableField<>();
 2     
 3     /**
 4      * 獲取服務器版本並判斷是否需要更新
 5      */
 6     public void getServiceAppVersionEvent() {
 7         resource.getAppVersionEvent()
 8                 .observeOn(AndroidSchedulers.mainThread())
 9                 .subscribe(response -> {
10                     if (EmptyUtil.isNotEmpty(response.body)) {
11                         appVersion.set(response.body);
12                         if (UpdateAppUtil.checkAppVersion(response.body)) {
13                             checkUpdate.set("發現新版本" + response.body.getVersion());
14                         }
15                     }
16                 });
17     }

服務器返回的數據

 1  2 
 3 /**
 4  * Created by hyx on 17-9-29.
 5  */
 6 
 7 public class VersionBean {
 8 
 9     private String description;
10     private String url;
11     private String version;
12 
13 
14 
15     public String getUrl() {
16         return url;
17     }
18 
19     public void setUrl(String url) {
20         this.url = url;
21     }
22 
23   
24 
25     public String getVersion() {
26         return version;
27     }
28 
29     public void setVersion(String version) {
30         this.version = version;
31     }
32 
33     public String getDescription() {
34         return description;
35     }
36 
37     public void setDescription(String description) {
38         this.description = description;
39     }
40 }

對比服務器和本地判斷是否需要更新,我這里是根據VersionName判斷

   /**
     * 獲取versionName
     *
     * @return
     */
    public static String getAppVersionName() {
        if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
            try {
                PackageManager manager = CtrAppImpl.getContext().getPackageManager();
                PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
                return info.versionName;
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }

        } else {
            return null;
        }
    }


    /**
     * 獲取versionId
     *
     * @return
     */
    public static int getAppVersionCode() {
        if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
            try {
                PackageManager manager = CtrAppImpl.getContext().getPackageManager();
                PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
                return info.versionCode;
            } catch (Exception e) {
                e.printStackTrace();
                return -1;
            }

        } else {
            return -1;
        }
    }

    /**
     * true 表示需要更新,false 表示當前版本是最新的
     *
     * @param versionBean
     * @return
     */
    public static boolean checkAppVersion(VersionBean versionBean) {
        if (EmptyUtil.isNotEmpty(versionBean)) {
            if (!getAppVersionName().equals(versionBean.getVersion())) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }

如果需要更新,我們根據存儲的downloadId去查詢下載狀態,因為有可能用戶之前已經下載了,沒有安裝,亦或正在下載中,下載暫停等情況,

 1  if (UpdateAppUtil.checkAppVersion(getViewModel().appVersion.get())) {
 2                 //根據downloadId查詢下載狀態
 3                 long downloadId = (long) SPUtil.get(PersonalActivity.this, "downloadId", -1L);
 4                 UpdateAppUtil.checkDownloadStatus(downloadId, new DataBack<Integer>() {
 5                     @Override
 6                     public void take(Integer status) {
 7                         if (status == -1) {
 8                             new MaterialDialog.Builder(PersonalActivity.this)
 9                                     .title("版本更新")
10                                     .content("發現新版本,是否更新?")
11                                     .positiveText("確定")
12                                     .negativeText("取消")
13                                     .onPositive(((materialDialog, dialogAction) -> {
14                                         ToastUtil.showShortToast("正在后台為您下載");
15                                         UpdateAppUtil.downloadAPK(getViewModel().appVersion.get(), "ctrshoppix.apk");
16                                     }))
17                                     .onNegative((materialDialog, dialogAction) -> {
18                                         materialDialog.dismiss();
19                                     })
20                                     .show();
21                         } else if (status == DownloadManager.STATUS_FAILED) {
22                             ToastUtil.showShortToast("下載失敗,正在為您重新下載");
23                             UpdateAppUtil.downloadAPK(getViewModel().appVersion.get(), "ctrshoppix.apk");
24                         } else if (status == DownloadManager.STATUS_SUCCESSFUL) {
25                             if (UpdateAppUtil.compareApk(UpdateAppUtil.getApkInfo(UpdateAppUtil.getDownloadPath(downloadId)))) {
26                                 UpdateAppUtil.installApp(UpdateAppUtil.getDownloadUri(downloadId));
27                             } else {
28                                 UpdateAppUtil.removeDownloadId(downloadId);
29                             }
30                         }
31                     }
32                 });

具體的方法在下面UpdateAppUtil中查看,備注寫的很清楚

  1 import android.app.Activity;
  2 import android.app.DownloadManager;
  3 import android.content.BroadcastReceiver;
  4 import android.content.Context;
  5 import android.content.Intent;
  6 import android.content.pm.PackageInfo;
  7 import android.content.pm.PackageManager;
  8 import android.database.Cursor;
  9 import android.net.Uri;
 10 import android.os.Build;
 11 import android.os.Environment;
 12 import android.support.v4.content.FileProvider;
 13 import android.text.BoringLayout;
 14 
 15 import java.io.File;
 16 import java.io.IOException;
 17 
 18 import ppm.ctr.cctv.ctr.application.CtrAppImpl;
 19 import ppm.ctr.cctv.ctr.common.AsyncCall;
 20 import ppm.ctr.cctv.ctr.common.DataBack;
 21 import ppm.ctr.cctv.ctr.network.entity.VersionBean;
 22 import ppm.ctr.cctv.ctr.services.file.UriPraseUtil;
 23 
 24 /**
 25  * Created by css on 2017/10/30.
 26  */
 27 
 28 public class UpdateAppUtil {
 29     private static DownloadManager downloadManager;
 30 
 31     /**
 32      * 獲取versionName
 33      *
 34      * @return
 35      */
 36     public static String getAppVersionName() {
 37         if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
 38             try {
 39                 PackageManager manager = CtrAppImpl.getContext().getPackageManager();
 40                 PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
 41                 return info.versionName;
 42             } catch (Exception e) {
 43                 e.printStackTrace();
 44                 return "";
 45             }
 46 
 47         } else {
 48             return null;
 49         }
 50     }
 51 
 52 
 53     /**
 54      * 獲取versionId
 55      *
 56      * @return
 57      */
 58     public static int getAppVersionCode() {
 59         if (EmptyUtil.isNotEmpty(CtrAppImpl.getContext())) {
 60             try {
 61                 PackageManager manager = CtrAppImpl.getContext().getPackageManager();
 62                 PackageInfo info = manager.getPackageInfo(CtrAppImpl.getContext().getPackageName(), 0);
 63                 return info.versionCode;
 64             } catch (Exception e) {
 65                 e.printStackTrace();
 66                 return -1;
 67             }
 68 
 69         } else {
 70             return -1;
 71         }
 72     }
 73 
 74     /**
 75      * true 表示需要更新,false 表示當前版本是最新的
 76      *
 77      * @param versionBean
 78      * @return
 79      */
 80     public static boolean checkAppVersion(VersionBean versionBean) {
 81         if (EmptyUtil.isNotEmpty(versionBean)) {
 82             if (!getAppVersionName().equals(versionBean.getVersion())) {
 83                 return true;
 84             } else {
 85                 return false;
 86             }
 87         }
 88         return false;
 89     }
 90 
 91     /**
 92      * 檢查下載狀態
 93      *
 94      * @param downloadId
 95      * @param dataBack
 96      */
 97     public static void checkDownloadStatus(long downloadId, DataBack<Integer> dataBack) {
 98         DownloadManager.Query query = new DownloadManager.Query();
 99         //通過下載的id查找
100         query.setFilterById(downloadId);
101         //獲取DownloadManager
102         if (EmptyUtil.isEmpty(downloadManager)) {
103             downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
104         }
105         Cursor c = downloadManager.query(query);
106         if (c.moveToFirst()) {
107             int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
108             switch (status) {
109                 case -1:
110                     dataBack.take(-1);
111                     break;
112                 //下載暫停
113                 case DownloadManager.STATUS_PAUSED:
114                     ToastUtil.showShortToast("下載暫停");
115                     break;
116                 //下載延遲
117                 case DownloadManager.STATUS_PENDING:
118                     ToastUtil.showShortToast("下載延遲");
119                     break;
120                 //正在下載
121                 case DownloadManager.STATUS_RUNNING:
122                     ToastUtil.showShortToast("正在下載");
123                     break;
124                 //下載完成
125                 case DownloadManager.STATUS_SUCCESSFUL:
126                     dataBack.take(DownloadManager.STATUS_SUCCESSFUL);
127 
128                     break;
129                 //下載失敗
130                 case DownloadManager.STATUS_FAILED:
131                     dataBack.take(DownloadManager.STATUS_FAILED);
132                     break;
133                 default:
134                     dataBack.take(-1);
135                     break;
136             }
137 
138             dataBack.take(status);
139         } else {
140             //可能用戶誤刪之前已經下載得apk
141             dataBack.take(-1);
142         }
143         c.close();
144     }
145 
146 
147     /**
148      * 根據downloadID獲取本地存儲的文件path
149      *
150      * @param downloadId
151      * @return
152      */
153     public static String getDownloadPath(long downloadId) {
154         //獲取DownloadManager
155         if (EmptyUtil.isEmpty(downloadManager)) {
156             downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
157         }
158         String downloadPath = new File(UriPraseUtil.uriToFile(downloadManager.getUriForDownloadedFile(downloadId), CtrAppImpl.getContext())).toString();
159         return downloadPath;
160     }
161 
162     /**
163      * 根據downloadID 獲取獲取本地文件存儲的uri
164      *
165      * @param downloadId
166      * @return
167      */
168     public static Uri getDownloadUri(long downloadId) {
169         //獲取DownloadManager
170         if (EmptyUtil.isEmpty(downloadManager)) {
171             downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
172         }
173         Uri downloadFileUri = downloadManager.getUriForDownloadedFile(downloadId);
174         //適配不同的手機,有的手機不能識別,所以再轉一遍
175         Uri uri = Uri.fromFile(new File(UriPraseUtil.uriToFile(downloadFileUri, CtrAppImpl.getContext())));
176         return uri;
177     }
178 
179 
180     /**
181      * 獲取apk程序信息
182      *
183      * @param path apk path
184      */
185     public static PackageInfo getApkInfo(String path) {
186         PackageManager pm = CtrAppImpl.getContext().getPackageManager();
187         PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
188         if (info != null) {
189             return info;
190         }
191         return null;
192     }
193 
194 
195     /**
196      * 下載的apk和當前程序版本比較
197      *
198      * @param apkInfo apk file's packageInfo
199      * @return 如果當前應用版本小於apk的版本則返回true
200      */
201     public static boolean compareApk(PackageInfo apkInfo) {
202         if (apkInfo == null) {
203             return false;
204         }
205         if (!apkInfo.versionName.equals(getAppVersionName())) {
206             return true;
207         }
208         return false;
209 
210     }
211 
212 
213     /**
214      * 下載apk
215      *
216      * @param versionBean
217      * @param apkName
218      */
219     public static void downloadAPK(VersionBean versionBean, String apkName) {
220         //創建下載任務
221         DownloadManager.Request request = new DownloadManager.Request(Uri.parse(versionBean.getUrl()));
222         //移動網絡情況下是否允許漫游
223         request.setAllowedOverRoaming(false);
224 //        設置在通知欄是否顯示下載通知(下載進度), 有 3 個值可選:
225 //        VISIBILITY_VISIBLE:                   下載過程中可見, 下載完后自動消失 (默認)
226 //        VISIBILITY_VISIBLE_NOTIFY_COMPLETED:  下載過程中和下載完成后均可見
227 //        VISIBILITY_HIDDEN:                    始終不顯示通知
228         request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
229         request.setTitle("單單拍");
230         request.setDescription("");
231         request.setVisibleInDownloadsUi(true);
232 
233         //設置下載的路徑
234         request.setDestinationInExternalPublicDir(Environment.getExternalStorageDirectory().getAbsolutePath(), apkName);
235 
236         //獲取DownloadManager
237         if (EmptyUtil.isEmpty(downloadManager)) {
238             downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
239         }
240         //將下載請求加入下載隊列,加入下載隊列后會給該任務返回一個long型的id,通過該id可以取消任務,重啟任務、獲取下載的文件等等
241         long downloadId = downloadManager.enqueue(request);
242         SPUtil.put(CtrAppImpl.getContext(), "downloadId", downloadId);
243     }
244 
245 
246     /**
247      * 移除本地存儲的downloadid 和相關文件
248      *
249      * @param downloadId
250      */
251     public static void removeDownloadId(long downloadId) {
252         //獲取DownloadManager
253         if (EmptyUtil.isEmpty(downloadManager)) {
254             downloadManager = (DownloadManager) CtrAppImpl.getContext().getSystemService(Context.DOWNLOAD_SERVICE);
255         }
256         downloadManager.remove(downloadId);
257         SPUtil.remove(CtrAppImpl.getContext(), "downloadId");
258     }
259 
260 
261     /**
262      * 安裝app
263      *
264      * @param uri
265      */
266     public static void installApp(Uri uri) {
267         Intent intent = new Intent();
268         intent.setDataAndType(uri, "application/vnd.android.package-archive");
269         intent.setAction(Intent.ACTION_VIEW);
270         intent.addCategory(Intent.CATEGORY_DEFAULT);
271         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
272         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
273         CtrAppImpl.getContext().startActivity(intent);
274     }
275 
276 
277     /**
278      * 安裝app
279      *
280      * @param apkPath
281      */
282     public static void installApp(String apkPath) {
283         File file = new File(apkPath);
284         Uri uri = null;
285         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
286             String command = "chmod " + "777" + " " + file;
287             Runtime runtime = Runtime.getRuntime();
288             try {
289                 runtime.exec(command);
290             } catch (IOException e) {
291                 e.printStackTrace();
292             }
293             uri = FileProvider.getUriForFile(CtrAppImpl.getContext(), "ppm.ctr.cctv.ctr.provider", file);
294         } else {
295             uri = Uri.fromFile(file);
296         }
297         Intent intent = new Intent();
298         intent.setDataAndType(uri, "application/vnd.android.package-archive");
299         intent.setAction(Intent.ACTION_VIEW);
300         intent.addCategory(Intent.CATEGORY_DEFAULT);
301         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
302         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
303         CtrAppImpl.getContext().startActivity(intent);
304     }
305 
306 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM