Android版本升級下載apk文件住练,UI進(jìn)度條顯示地啰,自動安裝apk的三種方式(AsyncTask、Service和使用DownloadManager)

我們主要指的是下載一個文件讲逛,不考慮斷點續(xù)傳亏吝。

主要的三種方式AsyncTask、Service和使用DownloadManager

一盏混、如果想要在后臺下載任務(wù)的同時可以更新進(jìn)度條UI----使用AsyncTask

asynctask效果gif

忽略安裝需要密碼這個細(xì)節(jié)蔚鸥,用oppo手機的應(yīng)該知道,這個是只有oppo測試機會這樣括饶,別的手機就可以直接安裝了株茶。

要點:

  • 一個url下載鏈接,一個ProgressDialog用來顯示進(jìn)度图焰,一個按鈕(點擊升級)按鈕監(jiān)聽的方法為onUpdateClick()

  • 接著放入主要的代碼

//關(guān)于進(jìn)度顯示
  private ProgressDialog progressDialog;
//相關(guān)屬性
        progressDialog =new ProgressDialog(UpdateDialogActivity.this);
        progressDialog.setMessage("正在下載...");
        progressDialog.setIndeterminate(true);
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progressDialog.setCancelable(true);
//升級下載按鈕點擊事件
 private void onUpdateClick() {
        // TODO: 2017/10/11 三種方式實現(xiàn)apk下載
       //第一種 asynctask
        //onProgressUpdate和onPreExecute是運行在UI線程中的启盛,
        // 所以我們應(yīng)該在這兩個方法中更新progress。
        final DownloadTask downloadTask = new DownloadTask(UpdateDialogActivity.this);
        //execute 執(zhí)行一個異步任務(wù),通過這個方法觸發(fā)異步任務(wù)的執(zhí)行僵闯。這個方法要在主線程調(diào)用卧抗。
        downloadTask.execute(url);
        progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                downloadTask.cancel(true);
            }
        });
    }
 private  class DownloadTask extends AsyncTask<String,Integer,String> {
        private Context context;
        private PowerManager.WakeLock mWakeLock;
        public DownloadTask(Context context) {
            this.context = context;
        }
        //onPreExecute(),在execute(Params... params)方法被調(diào)用后立即執(zhí)行,執(zhí)行在ui線程鳖粟,
        // 一般用來在執(zhí)行后臺任務(wù)前會UI做一些標(biāo)記
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            // take CPU lock to prevent CPU from going off if the user
            // presses the power button during download
            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                    getClass().getName());
            mWakeLock.acquire();
            progressDialog.show();
        }
        // doInBackground這個方法在onPreExecute()完成后立即執(zhí)行社裆,
        // 用于執(zhí)行較為耗時的操作,
        // 此方法接受輸入?yún)?shù)
        // 和返回計算結(jié)果(返回的計算結(jié)果將作為參數(shù)在任務(wù)完成是傳遞到onPostExecute(Result result)中)向图,
        // 在執(zhí)行過程中可以調(diào)用publishProgress(Progress... values)來更新進(jìn)度信息
        //后臺任務(wù)的代碼塊
        @Override
        protected String doInBackground(String... url) {
            InputStream input = null;
            OutputStream output = null;
            HttpURLConnection connection = null;
            try {
                URL urll=new URL(url[0]);
                Log.d("upgrade","url1:"+urll+"http:////url:"+url);
                connection = (HttpURLConnection) urll.openConnection();
                connection.connect();
                // expect HTTP 200 OK, so we don't mistakenly save error report
                // instead of the file
                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                    return "Server returned HTTP " + connection.getResponseCode()
                            + " " + connection.getResponseMessage();
                }
                // this will be useful to display download percentage
                // might be -1: server did not report the length
                int fileLength = connection.getContentLength();
                // download the file
                input = connection.getInputStream();
                output = new FileOutputStream("/sdcard/new.apk");
                byte data[] = new byte[4096];
                long total = 0;
                int count;
                while ((count = input.read(data)) != -1) {
                    if (isCancelled()) {
                        input.close();
                        return null;
                    }
                    total += count;
                    // publishing the progress....
                    if (fileLength > 0) // only if total length is known
                        //在調(diào)用這個方法后泳秀,執(zhí)行onProgressUpdate(Progress... values),
                        //運行在主線程榄攀,用來更新pregressbar
                        publishProgress((int) (total * 100 / fileLength));
                    output.write(data, 0, count);
                }
            } catch (Exception e) {
                return e.toString();
            } finally {
                try {
                    if (output != null)
                        output.close();
                    if (input != null)
                        input.close();
                } catch (IOException ignored) {
                }
                if (connection != null)
                    connection.disconnect();
            }
            return null;
        }
        //onProgressUpdate(Progress... values),
        // 執(zhí)行在UI線程嗜傅,在調(diào)用publishProgress(Progress... values)時,此方法被執(zhí)行檩赢。
        @Override
        protected void onProgressUpdate(Integer... progress) {
            super.onProgressUpdate(progress);
            // if we get here, length is known, now set indeterminate to false
            progressDialog.setIndeterminate(false);
            progressDialog.setMax(100);
            progressDialog.setProgress(progress[0]);
        }

        //onPostExecute(Result result),
        // 執(zhí)行在UI線程吕嘀,當(dāng)后臺操作結(jié)束時,此方法將會被調(diào)用贞瞒。
        @Override
        protected void onPostExecute(String result) {
            mWakeLock.release();
            progressDialog.dismiss();
            if (result != null)
                Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
            else
            {Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();}
//這里主要是做下載后自動安裝的處理
            File file=new File("/sdcard/new.apk");
            Intent installIntent = new Intent(Intent.ACTION_VIEW);
            installIntent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(installIntent);
        }

    }

二偶房、使用DownloadManager

每個Android App都會有版本更新的功能,而下載功能Google官方推薦使用 DownloadManager服務(wù)

使用最簡單的一種

download.gif
 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
                request.setDescription("下載中");
                request.setTitle("我的下載");
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {

                }
                request.allowScanningByMediaScanner();//設(shè)置可以被掃描到
                request.setVisibleInDownloadsUi(true);// 設(shè)置下載可見
                request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);//下載完成后通知欄任然可見
                request.setDestinationInExternalPublicDir(
                        Environment.DIRECTORY_DOWNLOADS, "my.apk");
                manager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
               // manager.enqueue(request);
                long Id = manager.enqueue(request);
                //listener(Id);
                SharedPreferences sPreferences = getActivity().getSharedPreferences(
                        "downloadapk", 0);
                sPreferences.edit().putLong("apk",Id).commit();//保存此次下載ID
                Log.d("shengji", "開始下載任務(wù):" + Id + " ...");

如果想同樣實現(xiàn)下載完安裝军浆,要使用廣播.當(dāng)DownloadManager下載完成后會發(fā)出一個廣播 android.intent.action.DOWNLOAD_COMPLETE棕洋,創(chuàng)建一個廣播接收者,處理自動提示安裝:

public class DownLoadBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        long completeId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
        Log.d("shengji","下載完成后的ID:"+completeId);
        SharedPreferences sPreferences =context.getSharedPreferences(
                "downloadapk", 0);
        long Id = sPreferences.getLong("apk", 0);
        if (Id==completeId){
            DownloadManager  manager =
                    (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
            Intent installIntent=new Intent(Intent.ACTION_VIEW);
            Uri downloadFileUri = manager
                    .getUriForDownloadedFile(completeId);
            installIntent.setDataAndType(downloadFileUri,
                    "application/vnd.android.package-archive");
            installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(installIntent);
        }
    }
}
在AndroidManifet中進(jìn)行注冊
      <receiver android:name=".receiver.DownLoadBroadcastReceiver">
            <intent-filter android:priority="20" >
                <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
            </intent-filter>
        </receiver>
還要加權(quán)限:
   <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

雖說代碼量很少瘾敢,但是也確實會有問題遇到

問題1:No Activity found to handle Intent

解決:首先不要單獨設(shè)置data和type拍冠, 要同時setDataAndType(data, "application/vnd.android.package-archive")尿这。其次最多的可能是下載文件路徑的問題簇抵,好好檢查文件路徑是否錯誤或是否不可讀。最簡單的方法就是把apk的路徑固定死

問題2:權(quán)限問題射众,targetSdkVersion >=23需要獲取權(quán)限才能自動安裝

解決:

方法一:把build.gradle 文件中的targetSdkVersion < 23碟摆。這種方式也是最簡單的。

方法二:動態(tài)的獲取權(quán)限:代碼如下

// getPersimmions();方法
 @TargetApi(23)
    private void getPersimmions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            ArrayList<String> permissions = new ArrayList<String>();
            /*
             * 讀寫權(quán)限和電話狀態(tài)權(quán)限非必要權(quán)限(建議授予)只會申請一次叨橱,用戶同意或者禁止典蜕,只會彈一次
             */
            // 讀寫權(quán)限
            if (addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
                permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny \n";
            }

            if (permissions.size() > 0) {
                requestPermissions(permissions.toArray(new String[permissions.size()]), SDK_PERMISSION_REQUEST);
            }
        }
    }
    @TargetApi(23)
    private boolean addPermission(ArrayList<String> permissionsList, String permission) {
        if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // 如果應(yīng)用沒有獲得對應(yīng)權(quán)限,則添加到列表中,準(zhǔn)備批量申請
            if (shouldShowRequestPermissionRationale(permission)){
                return true;
            }else{
                permissionsList.add(permission);
                return false;
            }

        }else{
            return true;
        }
    }

    @TargetApi(23)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        // TODO Auto-generated method stub
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    }

三、使用service(IntentService和ResultReceiver)

service.gif

IntentService繼承自service罗洗,在IntentService中我們開啟一個線程執(zhí)行下載任務(wù)(service和你的app其實是在一個線程中愉舔,因此不想阻塞主線程的話必須開啟新的線程。

//在這里根據(jù)url進(jìn)行下載文件伙菜,并通過receiver把需要更新的progressbar的值放在bundle傳過去
public class DownloadService extends IntentService {
    public static final int UPDATE_PROGRESS = 8344;
    public DownloadService() {
        super("DownloadService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        String urlToDownload = intent.getStringExtra("url");
        ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
        HttpURLConnection connection ;
        try {
            URL url = new URL(urlToDownload);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            // this will be useful so that you can show a typical 0-100% progress bar
            int fileLength = connection.getContentLength();
            Log.d("test","fileLength:"+fileLength);
            // download the file
            InputStream input = connection.getInputStream();
            OutputStream output = new FileOutputStream("/sdcard/new.apk");
            byte data[] = new byte[2048];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;
                // publishing the progress....
                Bundle resultData = new Bundle();
                resultData.putInt("progress" ,(int) (total * 100 / fileLength));
                receiver.send(UPDATE_PROGRESS, resultData);
                output.write(data, 0, count);
            }
            output.flush();
            output.close();
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
//記得注冊<service android:name=".DownloadService"/>

activity中這樣調(diào)用DownloadService

  progressDialog.show();                                                
  Intent intent = new Intent(this, DownloadService.class);              
  intent.putExtra("url",url);                                           
  intent.putExtra("receiver", new DownloadReceiver(new Handler()));     
  startService(intent);                                                 

activity中定義一個廣播接收器繼承ResultReceiver轩缤,ResultReceiver允許我們接收來自service中發(fā)出的廣播

 //使用ResultReceiver接收來自DownloadService的下載進(jìn)度通知                                                                
 private class DownloadReceiver extends ResultReceiver {                                                     
     public DownloadReceiver(Handler handler) {                                                              
         super(handler);                                                                                     
     }                                                                                                       

     @Override                                                                                               
     protected void onReceiveResult(int resultCode, Bundle resultData) {                                     
     super.onReceiveResult(resultCode, resultData);                                                          
         if (resultCode == DownloadService.UPDATE_PROGRESS) {                                                
             int progress = resultData.getInt("progress");                                                   
             //(true)就是根據(jù)你的進(jìn)度可以設(shè)置現(xiàn)在的進(jìn)度值。                                                                     
             //(false)就是滾動條的當(dāng)前值自動在最小到最大值之間來回移動,形成這樣一個動畫效果                                                    
             progressDialog.setIndeterminate(false);                                                         
             progressDialog.setProgress(progress);                                                           
             if (progress == 100) {                                                                          
                 progressDialog.dismiss();         
          //自動安裝下載的apk                                                          
                 File file=new File("/sdcard/new.apk");                                                      
                 Intent installIntent = new Intent(Intent.ACTION_VIEW);                                      
                 installIntent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                 installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);                                      
                 startActivity(installIntent);                                                               
             }                                                                                               
         }                                                                                                   
     }                                                                                                       
 }                                                                                                           

如果對您有用火的,給個贊鼓勵一下唄~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壶愤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子馏鹤,更是在濱河造成了極大的恐慌征椒,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件湃累,死亡現(xiàn)場離奇詭異勃救,居然都是意外死亡,警方通過查閱死者的電腦和手機治力,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門剪芥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人琴许,你說我怎么就攤上這事税肪。” “怎么了榜田?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵益兄,是天一觀的道長。 經(jīng)常有香客問我箭券,道長净捅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任辩块,我火速辦了婚禮蛔六,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘废亭。我一直安慰自己国章,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布豆村。 她就那樣靜靜地躺著液兽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掌动。 梳的紋絲不亂的頭發(fā)上四啰,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音粗恢,去河邊找鬼柑晒。 笑死,一個胖子當(dāng)著我的面吹牛眷射,可吹牛的內(nèi)容都是我干的匙赞。 我是一名探鬼主播恋追,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼罚屋!你這毒婦竟也來了苦囱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤脾猛,失蹤者是張志新(化名)和其女友劉穎撕彤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猛拴,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡赎瞎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年耐朴,在試婚紗的時候發(fā)現(xiàn)自己被綠了苫幢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碧信。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖跛溉,靈堂內(nèi)的尸體忽然破棺而出焊切,到底是詐尸還是另有隱情,我是刑警寧澤芳室,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布专肪,位于F島的核電站,受9級特大地震影響堪侯,放射性物質(zhì)發(fā)生泄漏嚎尤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一伍宦、第九天 我趴在偏房一處隱蔽的房頂上張望芽死。 院中可真熱鬧,春花似錦次洼、人聲如沸关贵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坪哄。三九已至,卻和暖如春势篡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背模暗。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工禁悠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人兑宇。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓碍侦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瓷产,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評論 25 707
  • Android Studio JNI流程首先在java代碼聲明本地方法 用到native關(guān)鍵字 本地方法不用去實現(xiàn)...
    MigrationUK閱讀 11,858評論 7 123
  • 小時候幻想仗劍走天涯 如今我到處流浪四海為家站玄。 她羨慕著別人乖巧的發(fā)卡 渴望著別人些許的關(guān)懷 最后假笑得像只厭惡的...
    BoombayahKAI閱讀 394評論 1 3
  • 上個月休年假株旷,我去了上海一趟看望我的閨蜜W姑娘,我在虹橋火車站地鐵口等著她來接我尔邓,我心里算了一下晾剖,我們大概有一年多...
    達(dá)達(dá)令閱讀 807評論 3 8
  • 你曾許下過一生只愛一個人的諾言嗎?在青春時光里梯嗽,我以為我會愛那個女孩一生一世齿尽。可是灯节,后來卻發(fā)現(xiàn)我卻不明白什么是愛循头,...
    Toooony閱讀 283評論 0 1