1. 程式人生 > >Android 使用系統自帶的DownloadManager下載apk

Android 使用系統自帶的DownloadManager下載apk

首先扯點別的:清明節回了一趟黃島,去了學校看了看,也是物是人非了呀。酒也沒少喝,前天做了一夜的車早上9點多到上海,然後直接殺奔公司上班,也是沒誰了。

今天記錄一下DownloadManager的使用。參考連結會在文章末尾給出。先來個效果圖。
這裡寫圖片描述

以下載一個萬能wifi鑰匙的安裝包為例。下載地址如下所示。

 private String wifiUrl = "http://140.207.247.205/imtt.dd.qq.com/16891/DF6B2FB4A4628C2870C710046C231348.apk?mkey=58d4b294acc7802a&f=8e5d&c=0&fsname=com.snda.wifilocating_4.1.88_3108.apk&csr=1bbd&p=.apk"
;

下載需要的許可權

 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

因為WRITE_EXTERNAL_STORAGE許可權是危險許可權,所以在使用的時候要進行動態許可權申請,我們使用easyPermissions來進行動態許可權申請。easypermissions的使用介紹可見下面的連線地址。

下面就開始使用DownLoadManager。
DownloadManager 簡介:DownloadManager一個是處理長期執行的HTTP下載的系統服務。客戶端請求的URI可以被被下載到一個特定的檔案。DownloadManager會在後臺進行下載,能很好的進行Http互動,在下載失敗,或者連線改變,重新啟動系統後重新下載。並且可以在Notification中檢視進度。DownloadManger有兩個內部類,Request 和Query。Request類可設定下載的一些屬性。Query類可查詢當前下載的進度,下載地址,檔案存放目錄等資料。

//獲取DownloadManager例項

DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

//新建一個下載請求, wifiUrl就是我們要下載的apk的地址。

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(wifiUrl));
//設定下載的檔案儲存的地址,我們這裡將下載的apk檔案存在/Download目錄下面        request.setDestinationInExternalPublicDir
(Environment.DIRECTORY_DOWNLOADS, "wifi.apk"); //設定現在的檔案可以被MediaScanner掃描到。 request.allowScanningByMediaScanner(); //設定通知的標題 request.setTitle("下載"); //設定下載的時候Notification的可見性。 request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //設定下載檔案型別 request.setMimeType("application/vnd.android.package-archive");

關於下載的request一些屬性的設定。

 /**
 設定下載的檔案的儲存地址位於公共的外部儲存目錄,和Environment.getExternalStoragePublicDirectory(String)返回的路徑一樣。
 下載的檔案不能被MediaScanner掃描到,但是可以呼叫request.allowScanningByMediaScanner()使下載的檔案可以被MediaScanner掃描到。
  @param dirType 儲存目錄型別
  @param subPath 在外部儲存目錄下面的路徑包括檔名
 */
 public Request setDestinationInExternalPublicDir(String dirType, String subPath)

比如我們在上面設定的儲存位置

//下載的apk檔案存在/Download目錄下面名字叫wifi.apk        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "wifi.apk");
/**
設定下載的檔案的儲存地址位於應用下的外部檔案目錄下,和Context#getExternalFilesDir(String)返回的路徑一樣。
*/
public Request setDestinationInExternalFilesDir(Context context, String dirType,String subPath)

設定在那種網路條件下可以進行下載

/**
flags取值
NETWORK_MOBILE 使用流量可以下載
NETWORK_WIFI 使用wifi可以下載

*/
 public Request setAllowedNetworkTypes(int flags)

控制在下載過程中或者下載完畢以後download manager 發出的系統通知是否可見

/**
visibility取值
VISIBILITY_VISIBLE 在下載過程中通知可見,下載完成後不可見
VISIBILITY_VISIBLE_NOTIFY_COMPLETED 在下載過程中和下載完成後都可見
VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION 只有在下載完成後通知才可見
VISIBILITY_HIDDEN 通知不可見,如果使用這個選項需要android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.許可權
*/
public Request setNotificationVisibility(int visibility)

開始下載

當 download manager準備好而且網路可用的時候就會自動開始下載,並且enqueue方法會返回一個唯一的id,可以用來查詢下載的進度,或者取消下載等等。

long id = downloadManager.enqueue(request);

查詢下載的進度
如果我們要在應用中顯示下載的進度,比如用一個ProgressBar來顯示下載的進度,這時候我們就要實時獲取的進度這時候就需要用到Query這個類了,這個類是DownloadManager中的一個內部類。

DownloadManager.Query query = new DownloadManager.Query();
//根據id進行查詢
Cursor cursor = downloadManager.query(query.setFilterById(id));
    if (cursor != null && cursor.moveToFirst()) {
        //已經下載的位元組數
        int bytesDownload = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
        //檔案的總的位元組數
        int bytesTotal = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

Query類中還有好多資訊可以查詢,因為我們這裡只關心下載進度的問題,其他的就不查了。

取消下載

//停止下載,並刪除下載的相關檔案,不管是否已經下載完成。
downloadManager.remove(id);

下載完apk進行安裝。要注意的一點就是,如果是7.0及以上的系統要是用FileProvider的方式構建Uri

 private void install(String path) {
        Uri uri;
        File file = new File(path);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //如果是7.0以上的系統,要使用FileProvider的方式構建Uri
            uri = FileProvider.getUriForFile(this, "com.hm.retrofitrxjavademo.fileprovider", file);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
        startActivity(intent);
    }

最後貼一下完整的程式碼

/**
 * 使用系統自帶的DownloadManager下載
 */
public class DownloadManagerActivity extends BaseActivity implements EasyPermissions.PermissionCallbacks {

    private static final String TAG = "DownloadManagerActivity";
    public static final String PROGRESS = "progress";
    private static final String[] PERMISSIONS = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
    public static final int REQUEST_CODE = 14;
    @BindView(R.id.btn_start)
    Button btnStart;
    @BindView(R.id.btn_cancel)
    Button btnCancel;
    @BindView(R.id.progressBar)
    ProgressBar progressBar;
    @BindView(R.id.textProgress)
    TextView textProgress;
    private String wifiUrl = "http://140.207.247.205/imtt.dd.qq.com/16891/DF6B2FB4A4628C2870C710046C231348.apk?mkey=58d4b294acc7802a&f=8e5d&c=0&fsname=com.snda.wifilocating_4.1.88_3108.apk&csr=1bbd&p=.apk";
    private long id;
    private DownloadManager downloadManager;
    private DownloadManager.Query query;

    private String downloadPath;
    private Timer timer;
    private TimerTask timerTask;
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Bundle bundle = msg.getData();
            int progress = bundle.getInt(PROGRESS);
            progressBar.setProgress(progress);
            textProgress.setText(String.valueOf(progress) + "%");
            if (progress == 100) {
                timer.cancel();
                install(downloadPath);
            }
        }
    };

    public static void launch(Context context) {
        Intent starter = new Intent(context, DownloadManagerActivity.class);
        context.startActivity(starter);
    }

    @Override
    protected int bindLayout() {
        return R.layout.activity_download_manager;
    }

    @Override
    protected void initData() {
        progressBar.setMax(100);
        query = new DownloadManager.Query();
    }

    @OnClick({R.id.btn_start, R.id.btn_cancel})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_start:
                if (EasyPermissions.hasPermissions(this, PERMISSIONS)) {
                    startDownLoad();
                } else {
                    EasyPermissions.requestPermissions(this, getString(R.string.rationale), REQUEST_CODE, PERMISSIONS);
                }
                break;
            case R.id.btn_cancel:
                cancelDownload();
                btnStart.setClickable(true);
                timer.cancel();
                textProgress.setText("");
                progressBar.setProgress(0);
                break;
        }
    }

    private void startDownLoad() {
        timer = new Timer();
        timerTask = new TimerTask() {
            @Override
            public void run() {
                queryProgress();
            }
        };
        btnStart.setClickable(false);
        downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(wifiUrl));
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "wifi.apk");
        downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath() + File.separator + "wifi.apk";
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        request.allowScanningByMediaScanner();
        request.setTitle("下載");
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        //設定下載檔案型別
        request.setMimeType("application/vnd.android.package-archive");
        id = downloadManager.enqueue(request);

        timer.schedule(timerTask, 0, 1000);
    }

    private void cancelDownload() {
        if (id != 0) {
            downloadManager.remove(id);
        }
    }

    private void queryProgress() {
        if (downloadManager != null) {
            Cursor cursor = downloadManager.query(query.setFilterById(id));
            if (cursor != null && cursor.moveToFirst()) {
                String address = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                //已經下載的位元組數
                int bytesDownload = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
                int bytesTotal = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
                String title = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_TITLE));
                String description = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION));
                long downloadId = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_ID));
                String uri = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_URI));
                int progress = bytesDownload * 100 / bytesTotal;
                Log.e(TAG, "progress=" + progress);
                Message message = Message.obtain();
                Bundle bundle = new Bundle();
                bundle.putInt(PROGRESS, progress);
                message.setData(bundle);
                handler.sendMessage(message);
            }
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    private void install(String path) {
        Uri uri;
        File file = new File(path);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //如果是7.0以上的系統,要使用FileProvider的方式構建Uri
            uri = FileProvider.getUriForFile(this, "com.hm.retrofitrxjavademo.fileprovider", file);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        }
        startActivity(intent);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

    @Override
    public void onPermissionsGranted(int requestCode, List<String> perms) {
        if (requestCode == REQUEST_CODE) {
            if (EasyPermissions.hasPermissions(this, PERMISSIONS)) {
                startDownLoad();
            } else {
                Toast.makeText(this, "沒有響應的許可權,無法進行下載", Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    public void onPermissionsDenied(int requestCode, List<String> perms) {
        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            new AppSettingsDialog.Builder(this)
                    .setRationale("下載需要讀寫許可權")
                    .setRequestCode(AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE)
                    .setTitle("請求許可權")
                    .setPositiveButton("設定")
                    .setNegativeButton("取消")
                    .build().show();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        timer.cancel();
    }
}

結尾:差不多該睡覺了。其實這段時間一直想跟她說說話,但是也不知道說啥,哎。明天一定找她說話,沒話題就製造話題,實在不行就問她最近學習忙不忙!