利用downloadmanager实现下载更新同时显示进度(兼容7.0)

利用系统downloadmanger实现下载更新,同时显示下载进度,不使用service。
android7.0之后,谷歌加强了权限控制,用原来的安装apk的方法会有异常。系统推荐使用fileprovider。修改方式如下:
<1>.在清单文件中注册

<provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

<2>在res目录下创建xml目录,在xml目录中添加provider_paths文件

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

<3>使用fileprovider。具体使用请看下面installApkByGuide方法。
思路:
1.先确定是否要更新
2.需要更新时获取安装包信息如大小版本号下载地址
3.代码中用的DownloadProgressDialog在上一篇文章
4.文章中的自定义弹窗CustomDialog在下一篇文章

xiazai.gif

具体实现:
1.首先添加联网和存储卡权限

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

2.代码实现


public class MainActivity extends AppCompatActivity {
    private DownloadManager mDownloadManager;
    //下载ID
    private long mDownloadId;
    //下载进度弹窗
    private DownloadProgressDialog progressDialog;
    //文件名
    private String mApkName;
    private final QueryRunnable mQueryProgressRunnable = new QueryRunnable();
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 1001) {
                if (progressDialog != null) {
                    progressDialog.setProgress(msg.arg1);
                    progressDialog.setMax(msg.arg2);
                }
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initReceiver();
        if (isNeedUpdate()) 
            DownloadApkInfo apkInfo = getDownloadApkInfo();
            if(apkInfo!=null) {
                startUpDate(apkInfo);
            }
        }
    }
    //初始化广播接收者
    private void initReceiver(){
        IntentFilter downloadCompleteFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
        registerReceiver(mDownloadCompleteReceiver, downloadCompleteFilter);
        IntentFilter downloadDetailsFilter = new IntentFilter(DownloadManager.ACTION_NOTIFICATION_CLICKED);
        registerReceiver(mDownloadDetailsReceiver, downloadDetailsFilter);
    }
    //是否需要下载更新
    private boolean isNeedUpdate() {
        return true;
    }
    //获取安装包信息
    private DownloadApkInfo getDownloadApkInfo(){
        DownloadApkInfo downloadApkInfo=new DownloadApkInfo();
        downloadApkInfo.setDownloadUrl("http://www.xxx.com/downloadmangedemo.apk");
        downloadApkInfo.setDescription("修复若干不可描述bug");
        downloadApkInfo.setDownloadSize(16.3f);
        downloadApkInfo.setVersionName("2.02");
        return downloadApkInfo;
    }
    //开始更新
    private void startUpDate(final DownloadApkInfo apkInfo) {
        mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        TipsUtils.showDialog(this, "发现新版本",
                apkInfo.getDescription(),
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startDownloadApk(apkInfo);
                    }
                }, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        stopQuery();
                        finish();
                    }
                }, "立即下载", "取消", false);
    }

    //开始下载apk文件
    private void startDownloadApk(DownloadApkInfo apkInfo) {
        mApkName= "DownloadManagerDemo" + "_v" + apkInfo.getVersionName() + ".apk";
        DownloadManager.Request request = new DownloadManager.Request(
                Uri.parse(apkInfo.getDownloadUrl()));
        request.setAllowedNetworkTypes(
                DownloadManager.Request.NETWORK_MOBILE
                        | DownloadManager.Request.NETWORK_WIFI)
                .setTitle("DownloadManagerDemo" + "_v" + apkInfo.getVersionName() + ".apk") // 用于信息查看
                .setDescription("新版本升级") // 用于信息查看
                .setDestinationInExternalPublicDir(
                        Environment.DIRECTORY_DOWNLOADS,
                       mApkName);
        try {
            mDownloadId = mDownloadManager.enqueue(request); // 加入下载队列
            startQuery();
        } catch (IllegalArgumentException e) {
            TipsUtils.showDialog(MainActivity.this,
                    "更新失败", "请在设置中开启下载管理",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            intent.setData(Uri.parse("package:" + "com.android.providers.downloads"));
                            if (intent.resolveActivity(getPackageManager()) != null) {
                                startActivity(intent);
                            }
                            finish();
                        }
                    }, null, "确定", "", false);
        }
    }
    //更新下载进度
    private void startQuery() {
        if (mDownloadId != 0) {
            displayProgressDialog();
            mHandler.post(mQueryProgressRunnable);
        }
    }
    //查询下载进度
    private class QueryRunnable implements Runnable {
        @Override
        public void run() {
            queryState();
            mHandler.postDelayed(mQueryProgressRunnable,100);
        }
    }
    //查询下载进度
    private void queryState() {
        // 通过ID向下载管理查询下载情况,返回一个cursor
        Cursor c = mDownloadManager.query(new DownloadManager.Query().setFilterById(mDownloadId));
        if (c == null) {
            Toast.makeText(this, "下载失败",Toast.LENGTH_SHORT).show();
            finish();
        } else { // 以下是从游标中进行信息提取
            if (!c.moveToFirst()) {
                Toast.makeText(this,"下载失败",Toast.LENGTH_SHORT).show();
                finish();
                if(!c.isClosed()) {
                    c.close();
                }
                return;
            }
            int mDownload_so_far = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
            int mDownload_all = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
            Message msg=Message.obtain();
            if(mDownload_all>0) {
                msg.what = 1001;
                msg.arg1=mDownload_so_far;
                msg.arg2=mDownload_all;
                mHandler.sendMessage(msg);
            }
            if(!c.isClosed()){
                c.close();
            }
        }
    }
    //停止查询下载进度
    private void stopQuery() {
        mHandler.removeCallbacks(mQueryProgressRunnable);
    }
    //下载停止同时删除下载文件
    private void removeDownload() {
        if(mDownloadManager!=null){
            mDownloadManager.remove(mDownloadId);
        }
    }
    //进度对话框
    private void displayProgressDialog() {
        if (progressDialog == null) {
            // 创建ProgressDialog对象
            progressDialog = new DownloadProgressDialog(this);
            // 设置进度条风格,风格为长形
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            // 设置ProgressDialog 标题
            progressDialog.setTitle("下载提示");
            // 设置ProgressDialog 提示信息
            progressDialog.setMessage("当前下载进度:");
            // 设置ProgressDialog 的进度条是否不明确
            progressDialog.setIndeterminate(false);
            // 设置ProgressDialog 是否可以按退回按键取消
            progressDialog.setCancelable(false);
            progressDialog.setProgressDrawable(getResources().getDrawable(R.drawable.download_progressdrawable));
            progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    removeDownload();
                    dialog.dismiss();
                    finish();
                }
            });
        }
        if (!progressDialog.isShowing()) {
            // 让ProgressDialog显示
            progressDialog.show();
        }
    }
    // 下载完成监听,下载完成之后自动安装
    private final BroadcastReceiver mDownloadCompleteReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
                long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
                // 查询
                DownloadManager.Query query = new DownloadManager.Query();
                query.setFilterById(downloadId);
                Cursor c = mDownloadManager.query(query);
                if (c!=null && c.moveToFirst()) {
                    int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
                    if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
                        String uriString =  Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath()+
                                File.separator+mApkName;
                        finish();
                        installApkByGuide(uriString);
                    }
                }
                if(c != null && ! c.isClosed()){
                    c.close();
                }
            }
        }
    };

    //安装apk
    private void installApkByGuide(String uriString) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        Uri uri;
        if(Build.VERSION.SDK_INT > = 24){
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            uri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", new File(localFilePath));
        }else{
            uri=Uri.fromFile(new File(localFilePath));
        }
        intent.setDataAndType(uri,
                "application/vnd.android.package-archive");
        context.startActivity(intent);
    }

    // 通知栏点击事件,点击进入下载详情
    private final BroadcastReceiver mDownloadDetailsReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(action)) {
                lookDownload();
            }
        }
    };
    //进入下载详情
    private void lookDownload() {
        Intent intent=new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
        if(intent.resolveActivity(getPackageManager())!=null){
            startActivity(intent);
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mDownloadCompleteReceiver!=null) {
            unregisterReceiver(mDownloadCompleteReceiver);
        }
        if(mDownloadDetailsReceiver!=null) {
            unregisterReceiver(mDownloadDetailsReceiver);
        }
    }
}

3.DownloadApkInfo

public class DownloadApkInfo {
    //下载地址
    private String downloadUrl;
    //更新内容
    private String description;
    //apk大小(单位是M)
    private float downloadSize;
    //显示版本号 如1.01
    private String versionName;

    public String getDownloadUrl() {
        return downloadUrl;
    }

    public void setDownloadUrl(String downloadUrl) {
        this.downloadUrl = downloadUrl;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public float getDownloadSize() {
        return downloadSize;
    }

    public void setDownloadSize(float downloadSize) {
        this.downloadSize = downloadSize;
    }

    public String getVersionName() {
        return versionName;
    }

    public void setVersionName(String versionName) {
        this.versionName = versionName;
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,392评论 25 707
  • 前言 自己写简书记录知识与看别人的简书、博客去学习有很大的区别,需要斟酌每一行代码的编写,认真的总结在编写代码过程...
    心若冰清_阅读 857评论 2 14
  • 我们使用手机的时候经常会看到应用程序提示升级,大部分应用内部都需要实现升级提醒和应用程序文件(APK文件)下载。 ...
    于连林520wcf阅读 33,755评论 43 149
  • 转载自于连林 我们使用手机的时候经常会看到应用程序提示升级,大部分应用内部都需要实现升级提醒和应用程序文件(APK...
    sirai阅读 1,099评论 0 24
  • 许久许久的日子里,她的生活就像一罐埋在沙里的炒干的花种。 怎么着都别扭。你看吧。心情干涸,爱干涸,有趣的想法。。。...
    平立罗阅读 207评论 1 1