Android 下载Apk文件(DownloadManager + HandlerThread)

212 阅读2分钟

创建HandlerThread

mWorkThread = new HandlerThread("download");
mWorkThread.start();

mHandler = new Handler(mWorkThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 1:// 开始下载
                String url = msg.obj.toString();
                downloadAPK(url, AppInfo.getVersionName(mContext.get()));
                break;
            case 2:
                checkDownloadStatus();//检查下载状态
                break;
            case 3:
                //下载完成安装APK
                String downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
                        + File.separator + AppInfo.getVersionName(mContext.get());
                installAPK(new File(downloadPath));
                mUpdateVersionDialog.dismiss();
                break;
        }
    }
};

下载

name 参数是你下载文件后文件的名字,安装时候要根据这个名字找到这个文件

  private void downloadAPK(String versionUrl, String name) {
        //创建下载任务
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(versionUrl));
        request.setAllowedOverRoaming(true);//漫游网络是否可以下载

        //设置文件类型,可以在下载结束后自动打开该文件
        MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
        String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(versionUrl));
        request.setMimeType(mimeString);

        //在通知栏中显示,默认就是显示的
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
        request.setVisibleInDownloadsUi(true);

        //sdcard的目录下的download文件夹
          request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,name);
//        request.setDestinationInExternalFilesDir(,"",getApkPath()),

        //将下载请求加入下载队列
        mDownloadManager = (DownloadManager) mContext.get().getSystemService(Context.DOWNLOAD_SERVICE);
        //加入下载队列后会给该任务返回id
        mTaskId = mDownloadManager.enqueue(request);

        mHandler.sendEmptyMessage(2);
    }

检查下载状态

//检查下载状态
private void checkDownloadStatus() {
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(mTaskId);//筛选下载任务,传入任务ID,可变参数
    Cursor c = mDownloadManager.query(query);
    if (c.moveToFirst()) {
        int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
        switch (status) {
            case DownloadManager.STATUS_PAUSED:
                Log.i("tag", ">>>下载暂停");
            case DownloadManager.STATUS_PENDING:
                Log.i("tag", ">>>下载延迟");
            case DownloadManager.STATUS_RUNNING:
                Log.e("tag", ">>>正在下载");
                setProgress(c);
                break;
            case DownloadManager.STATUS_SUCCESSFUL:
                Log.e("tag", ">>>下载完成");
                mHandler.sendEmptyMessage(3);
                break;
            case DownloadManager.STATUS_FAILED:
                Log.i("tag", ">>>下载失败");
                break;
        }
    }
}

显示下载进度

private void setProgress(Cursor c) {
    //已经下载的字节数
    int bytes_downloaded = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
    //总需下载的字节数
    int bytes_total = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
    if (bytes_downloaded != 0) {
        double progress = div(bytes_downloaded, bytes_total, 2);
        Log.e("tag", "checkDownloadStatus: " + bytes_downloaded + "-" + bytes_total + "-" + progress + "-" + (int) (progress * 100));
        mContext.get().runOnUiThread(() -> mUpdateVersionDialog.setProgress((int) (progress * 100)));
    }
    mHandler.sendEmptyMessageDelayed(2, 1000);
}

带小数点后两位的除法

public static double div(double v1, double v2, int scale) {
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
}

下载后安装

//下载到本地后执行安装
protected void installAPK() {
    String downloadPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
            + File.separator + AppInfo.getVersionName(mContext.get());
    File file = new File(downloadPath);
    if (!file.exists()) return;
    //参数2配置文件中一致   参数3  download文件夹位置
    Uri apkUri = FileProvider.getUriForFile(mContext.get(), "xxx", file);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    // 由于没有在Activity环境下启动Activity,设置下面的标签
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    //添加这一句表示对目标应用临时授权该Uri所代表的文件
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
    mContext.get().startActivity(intent);
}


file_paths.xml :用FileProvider需要建一个xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <paths>
        <external-path path="" name="download"/>
    </paths>

</resources>
并在清单文件中加provider 
<provider
    android:name="androidx.core.content.FileProvider"
    android:authorities="xxx"
    android:grantUriPermissions="true"
    android:exported="false">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

补充:权限

<!--安装应用权限-->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.INTERNET" />