Android webview通過http get下載檔案下載兩次的相關問題及解決方案

來源:互聯網
上載者:User

一、現象

   一般通過Android webview進行下載檔案的方法是

   1.重寫DownloadListener的onDownloadStart方法,在onDownloadStart方法中彈出對話方塊提示使用者有新的檔案需要下載

   2.使用者點擊確定之後,通過http get下載檔案

   由於Android webview的實現,以上的下載檔案步驟涉及到了兩次get的操作。第一次是使用者在webview中點擊下載連結時,webview自動發送http get請求,這個時候伺服器除了將檔案資訊發送過來之外,會同時將檔案的內容發送給webview。第二次是在步驟2,由自己設計的程式發起的。

   為了驗證如上結論,我在Android 4.4系統中的內建瀏覽器通過訪問並下載這個測試連結,並用wireshark進行抓包查看結果。通過如下三張圖,我覺得可以驗證同一份檔案確實被傳了兩次。因為兩個不同http get請求之後都可以看到伺服器向用戶端發送的連續的TCP資料包。

二、解決方案

   針對這個問題,我覺得比較完美的解決辦法是webview在進行get的時候能夠緩衝相應的檔案內容,並且開放相應的介面給應用進行緩衝的讀取。但是我並沒有發現相應的api。

   於是便有了如下的解決辦法:在webview載入url之前,通過連結中的一些特定欄位發現進行下載操作。然後通過http head請求擷取檔案名稱和大小等相關資訊。由於http head只是請求檔案相關資訊,所以伺服器只是通過http response將檔案資訊返回而不通過tcp傳送檔案具體內容。

2.1 在繼承自WebViewClient的類的shouldOverrideUrlLoading方法中檢查連結類型,並通過http head擷取檔案大小,名稱資訊。在以下代碼基礎上需要增加合適的擷取檔案名稱代碼和handler的代碼。

if (url.contains("可能會進行下載的連結欄位")) {new Thread() {public void run() {HttpHead httpGet = new HttpHead(mUrl);boolean success = true;String filename="";Integer fileLength=100;try {HttpParams httpParameters = new BasicHttpParams();        HttpConnectionParams.setConnectionTimeout(httpParameters, 8000);        HttpConnectionParams.setSoTimeout(httpParameters, 8000);DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
//需要的話可能得增加cookie
HttpResponse httpResponse = httpClient.execute(httpGet);if (httpResponse.getStatusLine().getStatusCode() == 200) {                  //如果檔案名稱儲存在Content-Disposition中,並且用的是gb2312編碼方式可以參考這段代碼String nameString=httpResponse.getFirstHeader("Content-Disposition").getValue();char [] nameChar=new char[nameString.length()];byte [] nameBytes=new byte[nameString.length()];nameString.getChars(0, nameString.length(), nameChar, 0);for (int i = 0; i < nameChar.length; i++) {nameBytes[i]=(byte)nameChar[i];}filename=EncodingUtils.getString(nameBytes, "gb2312");Log.d(TAG, "file name is "+filename);String contentLength=httpResponse.getFirstHeader("Content-Length").getValue();fileLength=Integer.parseInt(contentLength);success=true;}else {success=false;}} catch (Exception e) {success = false;e.printStackTrace();}Message msg = Message.obtain();if(success) {msg.what = GET_FILE_INFO_FINISHED;Bundle mBundle=new Bundle();mBundle.putString("fileName", filename);mBundle.putInt("fileLength", fileLength);msg.setData(mBundle);}else {msg.what = GET_FILE_INFO_FAILED;}mHandler.sendMessage(msg);}}.start();}else {view.loadUrl(url);}

2.2 適用情況

   在Android 4.4中,根據網頁的特點,可能會出現點擊下載連結,而shouldOverrideUrlLoading不被調用的情況,這時2.1中方法則失效了。不過對於4.4之前的系統應該是適用的。

三、參考材料

3.1 http://stackoverflow.com/questions/11801787/webview-cant-download-file-without-requesting-it-twice

3.2 http://stackoverflow.com/questions/12535414/is-setdownloadlistener-ondownloadstart-called-after-the-webview-already-gets-the

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.