利用downloadmanager實(shí)現(xiàn)下載更新同時(shí)顯示進(jìn)度(兼容7.0)

利用系統(tǒng)downloadmanger實(shí)現(xiàn)下載更新,同時(shí)顯示下載進(jìn)度,不使用service。
android7.0之后,谷歌加強(qiáng)了權(quán)限控制,用原來的安裝apk的方法會(huì)有異常。系統(tǒng)推薦使用fileprovider。修改方式如下:
<1>.在清單文件中注冊(cè)

<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目錄下創(chuàng)建xml目錄,在xml目錄中添加provider_paths文件

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

<3>使用fileprovider。具體使用請(qǐng)看下面installApkByGuide方法。
思路:
1.先確定是否要更新
2.需要更新時(shí)獲取安裝包信息如大小版本號(hào)下載地址
3.代碼中用的DownloadProgressDialog在上一篇文章
4.文章中的自定義彈窗CustomDialog在下一篇文章

xiazai.gif

具體實(shí)現(xiàn):
1.首先添加聯(lián)網(wǎng)和存儲(chǔ)卡權(quán)限

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

2.代碼實(shí)現(xiàn)


public class MainActivity extends AppCompatActivity {
    private DownloadManager mDownloadManager;
    //下載ID
    private long mDownloadId;
    //下載進(jìn)度彈窗
    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("修復(fù)若干不可描述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, "發(fā)現(xiàn)新版本",
                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("新版本升級(jí)") // 用于信息查看
                .setDestinationInExternalPublicDir(
                        Environment.DIRECTORY_DOWNLOADS,
                       mApkName);
        try {
            mDownloadId = mDownloadManager.enqueue(request); // 加入下載隊(duì)列
            startQuery();
        } catch (IllegalArgumentException e) {
            TipsUtils.showDialog(MainActivity.this,
                    "更新失敗", "請(qǐng)?jiān)谠O(shè)置中開啟下載管理",
                    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);
        }
    }
    //更新下載進(jìn)度
    private void startQuery() {
        if (mDownloadId != 0) {
            displayProgressDialog();
            mHandler.post(mQueryProgressRunnable);
        }
    }
    //查詢下載進(jìn)度
    private class QueryRunnable implements Runnable {
        @Override
        public void run() {
            queryState();
            mHandler.postDelayed(mQueryProgressRunnable,100);
        }
    }
    //查詢下載進(jìn)度
    private void queryState() {
        // 通過ID向下載管理查詢下載情況,返回一個(gè)cursor
        Cursor c = mDownloadManager.query(new DownloadManager.Query().setFilterById(mDownloadId));
        if (c == null) {
            Toast.makeText(this, "下載失敗",Toast.LENGTH_SHORT).show();
            finish();
        } else { // 以下是從游標(biāo)中進(jìn)行信息提取
            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();
            }
        }
    }
    //停止查詢下載進(jìn)度
    private void stopQuery() {
        mHandler.removeCallbacks(mQueryProgressRunnable);
    }
    //下載停止同時(shí)刪除下載文件
    private void removeDownload() {
        if(mDownloadManager!=null){
            mDownloadManager.remove(mDownloadId);
        }
    }
    //進(jìn)度對(duì)話框
    private void displayProgressDialog() {
        if (progressDialog == null) {
            // 創(chuàng)建ProgressDialog對(duì)象
            progressDialog = new DownloadProgressDialog(this);
            // 設(shè)置進(jìn)度條風(fēng)格,風(fēng)格為長(zhǎng)形
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            // 設(shè)置ProgressDialog 標(biāo)題
            progressDialog.setTitle("下載提示");
            // 設(shè)置ProgressDialog 提示信息
            progressDialog.setMessage("當(dāng)前下載進(jìn)度:");
            // 設(shè)置ProgressDialog 的進(jìn)度條是否不明確
            progressDialog.setIndeterminate(false);
            // 設(shè)置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();
        }
    }
    // 下載完成監(jiān)聽,下載完成之后自動(dòng)安裝
    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);
    }

    // 通知欄點(diǎn)擊事件,點(diǎn)擊進(jìn)入下載詳情
    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();
            }
        }
    };
    //進(jìn)入下載詳情
    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;
    //更新內(nèi)容
    private String description;
    //apk大小(單位是M)
    private float downloadSize;
    //顯示版本號(hào) 如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;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,813評(píng)論 25 708
  • 前言 自己寫簡(jiǎn)書記錄知識(shí)與看別人的簡(jiǎn)書、博客去學(xué)習(xí)有很大的區(qū)別,需要斟酌每一行代碼的編寫,認(rèn)真的總結(jié)在編寫代碼過程...
    心若冰清_閱讀 887評(píng)論 2 14
  • 我們使用手機(jī)的時(shí)候經(jīng)常會(huì)看到應(yīng)用程序提示升級(jí),大部分應(yīng)用內(nèi)部都需要實(shí)現(xiàn)升級(jí)提醒和應(yīng)用程序文件(APK文件)下載。 ...
    于連林520wcf閱讀 33,998評(píng)論 43 149
  • 轉(zhuǎn)載自于連林 我們使用手機(jī)的時(shí)候經(jīng)常會(huì)看到應(yīng)用程序提示升級(jí),大部分應(yīng)用內(nèi)部都需要實(shí)現(xiàn)升級(jí)提醒和應(yīng)用程序文件(APK...
    sirai閱讀 1,181評(píng)論 0 24
  • 許久許久的日子里,她的生活就像一罐埋在沙里的炒干的花種。 怎么著都別扭。你看吧。心情干涸,愛干涸,有趣的想法。。。...
    平立羅閱讀 222評(píng)論 1 1