每一個Android App都會有版本更新的功能,而下載功能Google官方推薦使用 DownloadManager
服務, 一塊兒來看看如何使用DownloadManager實現版本更新的功能。java
/** * 下載Apk, 並設置Apk地址, * 默認位置: /storage/sdcard0/Download * * @param context 上下文 * @param downLoadUrl 下載地址 * @param infoName 通知名稱 * @param description 通知描述 */ @SuppressWarnings("unused") public static void downloadApk( Context context, String downLoadUrl, String description, String infoName) { DownloadManager.Request request; try { request = new DownloadManager.Request(Uri.parse(appUrl)); } catch (Exception e) { e.printStackTrace(); return; } request.setTitle(infoName); request.setDescription(description); //在通知欄顯示下載進度 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); } //設置保存下載apk保存路徑 request.setDestinationInExternalPublicDir(CommonCons.SAVE_APP_LOCATION, CommonCons.SAVE_APP_NAME); Context appContext = context.getApplicationContext(); DownloadManager manager = (DownloadManager) appContext.getSystemService(Context.DOWNLOAD_SERVICE); //進入下載隊列 manager.enqueue(request); }
當DownloadManager下載完成後會發出一個廣播 android.intent.action.DOWNLOAD_COMPLETE,建立一個廣播接收者,處理自動提示安裝:android
/** * 安裝下載接收器 * Created by maimingliang on 2016/8/11. */ public class InstallReceiver extends BroadcastReceiver { private static final String TAG = "InstallReceiver"; // 安裝下載接收器 @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { installApk(context); } } // 安裝Apk private void installApk(Context context) { try { Intent i = new Intent(Intent.ACTION_VIEW); String filePath = CommonCons.APP_FILE_NAME; i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive"); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); }catch (Exception e){ Log.e(TAG,"安裝失敗"); e.printStackTrace(); } }
能夠看出,實現起來實際上是很容易的。不過要注意下面的幾個坑:git
圖上報錯的緣由是 targetSdkVersion >=23 致使的,在API23之後引入了動態權限的概念。github
如何解決?有兩種方式:app
方法一:ide
把build.gradle 文件中的targetSdkVersion < 23。這種方式也是最簡單的。gradle
方法二:ui
動態的獲取權限:spa
@TargetApi(23) private void getPersimmions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { ArrayList<String> permissions = new ArrayList<String>(); /* * 讀寫權限和電話狀態權限非必要權限(建議授予)只會申請一次,用戶贊成或者禁止,只會彈一次 */ // 讀寫權限 if (addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny \n"; } if (permissions.size() > 0) { requestPermissions(permissions.toArray(new String[permissions.size()]), SDK_PERMISSION_REQUEST); } } } @TargetApi(23) private boolean addPermission(ArrayList<String> permissionsList, String permission) { if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // 若是應用沒有得到對應權限,則添加到列表中,準備批量申請 if (shouldShowRequestPermissionRationale(permission)){ return true; }else{ permissionsList.add(permission); return false; } }else{ return true; } } @TargetApi(23) @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { // TODO Auto-generated method stub super.onRequestPermissionsResult(requestCode, permissions, grantResults); }
有兩種緣由:scala
緣由一:
沒有權限讀取這個文件或者文件路徑錯誤。
解決方案:
把apk的路徑固定死
String filePath = CommonCons.APP_FILE_NAME;
緣由二:
單獨設置data和type,以下:
i.setData(Uri.parse("file://" + filePath));
i.setType( "application/vnd.android.package-archive");
沒有設置FLAG_ACTIVITY_NEW_TASK
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
APK簽名不一致, 好比以前是debug版 如今你更新安裝release版 .
DownloadManager 下載完 apk 自動提示安裝Demo
END.