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

利用系統(tǒng)downloadmanger實現(xiàn)下載更新讥耗,同時顯示下載進度打厘,不使用service。
android7.0之后秫逝,谷歌加強了權(quán)限控制恕出,用原來的安裝apk的方法會有異常。系統(tǒng)推薦使用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目錄下創(chuàng)建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

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

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

2.代碼實現(xiàn)


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("修復(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("新版本升級") // 用于信息查看
                .setDestinationInExternalPublicDir(
                        Environment.DIRECTORY_DOWNLOADS,
                       mApkName);
        try {
            mDownloadId = mDownloadManager.enqueue(request); // 加入下載隊列
            startQuery();
        } catch (IllegalArgumentException e) {
            TipsUtils.showDialog(MainActivity.this,
                    "更新失敗", "請在設(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);
        }
    }
    //更新下載進度
    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) {
            // 創(chuàng)建ProgressDialog對象
            progressDialog = new DownloadProgressDialog(this);
            // 設(shè)置進度條風格,風格為長形
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            // 設(shè)置ProgressDialog 標題
            progressDialog.setTitle("下載提示");
            // 設(shè)置ProgressDialog 提示信息
            progressDialog.setMessage("當前下載進度:");
            // 設(shè)置ProgressDialog 的進度條是否不明確
            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)聽尝胆,下載完成之后自動安裝
    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;
    //更新內(nèi)容
    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;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市含衔,隨后出現(xiàn)的幾起案子煎娇,更是在濱河造成了極大的恐慌二庵,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缓呛,死亡現(xiàn)場離奇詭異催享,居然都是意外死亡,警方通過查閱死者的電腦和手機哟绊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門因妙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人匿情,你說我怎么就攤上這事兰迫⌒攀猓” “怎么了炬称?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長涡拘。 經(jīng)常有香客問我玲躯,道長,這世上最難降的妖魔是什么鳄乏? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任跷车,我火速辦了婚禮,結(jié)果婚禮上橱野,老公的妹妹穿的比我還像新娘朽缴。我一直安慰自己,他們只是感情好水援,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布密强。 她就那樣靜靜地躺著,像睡著了一般蜗元。 火紅的嫁衣襯著肌膚如雪或渤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天奕扣,我揣著相機與錄音薪鹦,去河邊找鬼。 笑死惯豆,一個胖子當著我的面吹牛池磁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播楷兽,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼框仔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拄养?” 一聲冷哼從身側(cè)響起离斩,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤银舱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后跛梗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寻馏,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年核偿,在試婚紗的時候發(fā)現(xiàn)自己被綠了诚欠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡漾岳,死狀恐怖轰绵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尼荆,我是刑警寧澤左腔,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站捅儒,受9級特大地震影響液样,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巧还,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一鞭莽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧麸祷,春花似錦澎怒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荸恕,卻和暖如春乖酬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背融求。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工咬像, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人生宛。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓县昂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親陷舅。 傳聞我的和親對象是個殘疾皇子倒彰,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

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

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