三种方式让 Android WebView 支持文件下载
三種方式讓 Android WebView 支持文件下載
?
最近在開發(fā)的過程中遇到一個需求,那就是讓 WebView 支持文件下載,比如說下載 apk。WebView 默認(rèn)是不支持下載的,需要開發(fā)者自己實(shí)現(xiàn)。既然 PM 提出了需求,那咱就擼起袖子干唄,于是乎在網(wǎng)上尋找了幾種方法,主要思路有這么幾種:
- 跳轉(zhuǎn)瀏覽器下載
- 使用系統(tǒng)的下載服務(wù)
- 自定義下載任務(wù)
有了思路就好辦了,下面介紹具體實(shí)現(xiàn)。
要想讓 WebView 支持下載,需要給 WebView 設(shè)置下載監(jiān)聽器?setDownloadListener,DownloadListener 里面只有一個方法 onDownloadStart,每當(dāng)有文件需要下載時,該方法就會被回調(diào),下載的 URL 通過方法參數(shù)傳遞,我們可以在這里處理下載事件。
?
mWebView.setDownloadListener(new DownloadListener() {@Overridepublic void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {// TODO: 2017-5-6 處理下載事件}});1. 跳轉(zhuǎn)瀏覽器下載
這種方式最為簡單粗暴,直接把下載任務(wù)拋給瀏覽器,剩下的就不用我們管了。缺點(diǎn)是無法感知下載完成,當(dāng)然就沒有后續(xù)的處理,比如下載 apk 完成后打開安裝界面。
private void downloadByBrowser(String url) {Intent intent = new Intent(Intent.ACTION_VIEW);intent.addCategory(Intent.CATEGORY_BROWSABLE);intent.setData(Uri.parse(url));startActivity(intent);}?
?
2. 使用系統(tǒng)的下載服務(wù)
DownloadManager 是系統(tǒng)提供的用于處理下載的服務(wù),使用者只需提供下載 URI 和存儲路徑,并進(jìn)行簡單的設(shè)置。DownloadManager 會在后臺進(jìn)行下載,并且在下載失敗、網(wǎng)絡(luò)切換以及系統(tǒng)重啟后嘗試重新下載。
? private void downloadBySystem(String url, String contentDisposition, String mimeType) {// 指定下載地址DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));// 允許媒體掃描,根據(jù)下載的文件類型被加入相冊、音樂等媒體庫request.allowScanningByMediaScanner();// 設(shè)置通知的顯示類型,下載進(jìn)行時和完成后顯示通知request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);// 設(shè)置通知欄的標(biāo)題,如果不設(shè)置,默認(rèn)使用文件名// request.setTitle("This is title");// 設(shè)置通知欄的描述// request.setDescription("This is description");// 允許在計(jì)費(fèi)流量下下載request.setAllowedOverMetered(false);// 允許該記錄在下載管理界面可見request.setVisibleInDownloadsUi(false);// 允許漫游時下載request.setAllowedOverRoaming(true);// 允許下載的網(wǎng)路類型request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);// 設(shè)置下載文件保存的路徑和文件名String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);log.debug("fileName:{}", fileName);request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);// 另外可選一下方法,自定義下載路徑// request.setDestinationUri()// request.setDestinationInExternalFilesDir()final DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);// 添加一個下載任務(wù)long downloadId = downloadManager.enqueue(request);log.debug("downloadId:{}", downloadId);}這樣我們就添加了一項(xiàng)下載任務(wù),然后就靜靜等待系統(tǒng)下載完成吧。還要注意一點(diǎn),別忘了添加讀寫外置存儲權(quán)限和網(wǎng)絡(luò)權(quán)限哦~
那怎么知道文件下載成功呢?系統(tǒng)在下載完成后會發(fā)送一條廣播,里面有任務(wù) ID,告訴調(diào)用者任務(wù)完成,通過 DownloadManager 獲取到文件信息就可以進(jìn)一步處理。
Ok,到這里,利用系統(tǒng)服務(wù)下載就算結(jié)束了,簡單總結(jié)一下。我們只關(guān)心開始和完成,至于下載過程中的暫停、重試等機(jī)制,系統(tǒng)已經(jīng)幫我們做好了,是不是非常友好?
3. 自定義下載任務(wù)
有了下載鏈接就可以自己實(shí)現(xiàn)網(wǎng)絡(luò)部分,我在這兒自定義了一個下載任務(wù),使用 HttpURLConnection 和 AsyncTask 實(shí)現(xiàn),代碼還是比較簡單的。
? private class DownloadTask extends AsyncTask<String, Void, Void> {// 傳遞兩個參數(shù):URL 和 目標(biāo)路徑private String url;private String destPath;@Overrideprotected void onPreExecute() {log.info("開始下載");}@Overrideprotected Void doInBackground(String... params) {log.debug("doInBackground. url:{}, dest:{}", params[0], params[1]);url = params[0];destPath = params[1];OutputStream out = null;HttpURLConnection urlConnection = null;try {URL url = new URL(params[0]);urlConnection = (HttpURLConnection) url.openConnection();urlConnection.setConnectTimeout(15000);urlConnection.setReadTimeout(15000);InputStream in = urlConnection.getInputStream();out = new FileOutputStream(params[1]);byte[] buffer = new byte[10 * 1024];int len;while ((len = in.read(buffer)) != -1) {out.write(buffer, 0, len);}in.close();} catch (IOException e) {log.warn(e);} finally {if (urlConnection != null) {urlConnection.disconnect();}if (out != null) {try {out.close();} catch (IOException e) {log.warn(e);}}}return null;}@Overrideprotected void onPostExecute(Void aVoid) {log.info("完成下載");Intent handlerIntent = new Intent(Intent.ACTION_VIEW);String mimeType = getMIMEType(url);Uri uri = Uri.fromFile(new File(destPath));log.debug("mimiType:{}, uri:{}", mimeType, uri);handlerIntent.setDataAndType(uri, mimeType);startActivity(handlerIntent);}}private String getMIMEType(String url) {String type = null;String extension = MimeTypeMap.getFileExtensionFromUrl(url);log.debug("extension:{}", extension);if (extension != null) {type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);}return type;}// 使用mWebView.setDownloadListener(new DownloadListener() {@Overridepublic void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);String destPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + File.separator + fileName;new DownloadTask().execute(url, destPath);}});優(yōu)勢是我們可以感知下載進(jìn)度,處理開始、取消、失敗、完成等事件,不足之處是對下載的控制不如系統(tǒng)服務(wù),必須自己處理網(wǎng)絡(luò)帶來的問題。
可以看出,這三種下載方式各有特點(diǎn),大家可以根據(jù)需要選擇。
總結(jié)
以上是生活随笔為你收集整理的三种方式让 Android WebView 支持文件下载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022年G2电站锅炉司炉复习题及模拟考
- 下一篇: OpenCV图像拼接和图像融合技术