Android 使用系统自带的DownloadManager下载apk

首先扯点别的:清明节回了一趟黄岛,去了学校看了看,也是物是人非了呀。酒也没少喝,前天做了一夜的车早上9点多到上海,然后直接杀奔公司上班,也是没谁了。

完整代码请参考 DownloadManagerActivity

今天记录一下DownloadManager的使用。参考链接会在文章末尾给出。先来个效果图。
Android 使用系统自带的DownloadManager下载apk_第1张图片

以下载一个万能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的使用介绍可见下面的连接地址。

https://github.com/googlesamples/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();
    }
}

结尾:差不多该睡觉了。其实这段时间一直想跟她说说话,但是也不知道说啥,哎。明天一定找她说话,没话题就制造话题,实在不行就问她最近学习忙不忙!

参考链接

  1. http://blog.csdn.net/u012209506/article/details/56012744
  2. easyPermissions的使用https://github.com/googlesamples/easypermissions
  3. FileProvider的使用http://blog.csdn.net/leilifengxingmw/article/details/57405908

你可能感兴趣的:(Android)