I. symptom
Generally, the method for downloading files through Android webview is
1. Override the ondownloadloadstart method of DownloadListener. In the onDownloadStart method, a dialog box is displayed, prompting users to download new files.
2. Click OK to download the file through http get.
Due to the implementation of Android webview, the above steps involve two get operations. For the first time, when a user clicks the download link in webview, webview automatically sends an http get request. In this case, the server sends the file information to webview at the same time. The second was initiated by a self-designed program in step 2.
In order to verify the above conclusion, I access and download this test link from my browser in Android 4.4 and use wireshark to capture packets and view the results. In the following three figures, I think we can verify that the same file has been uploaded twice. Because after two different http get requests, you can see the continuous TCP packet sent by the server to the client.
Ii. Solution
To address this problem, I think the perfect solution is that webview can cache the corresponding file content during get and open the corresponding interfaces to read the application cache. However, I did not find the corresponding api.
Therefore, the following solution is available: Before webview loads a url, some specific fields in the link are found to be downloaded. Then, get the file name, size, and other information through the http head request. Because http head only requests file-related information, the server only returns the file information through http response instead of sending the specific file content through tcp.
2.1 check the link type in the shouldOverrideUrlLoading method of the class inherited from WebViewClient, and obtain the file size and name information through the http head. Add the appropriate code for getting the file name and handler based on the following code.
If (url. contains ("link fields that may be downloaded") {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 );
// You may need to add a cookie if necessary.
HttpResponse httpResponse = httpClient.exe cute (httpGet); if (httpResponse. getStatusLine (). getStatusCode () = 200) {// if the file name is saved in Content-Disposition and encoded using gb2312, refer to the code 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 Applicability
In Android 4.4, the download link may be clicked based on the characteristics of the webpage, but shouldOverrideUrlLoading is not called. In this case, the Chinese rule 2.1 becomes invalid. However, it should be applicable to systems earlier than 4.4.
Iii. References
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