Webビューでダウンロードをサポート

13913 ワード

最近、開発の過程で、WebViewがapkのダウンロードなどのファイルのダウンロードをサポートする必要があります.WebViewのデフォルトではダウンロードはサポートされていません.開発者が自分で実現する必要があります.PMが需要を提出した以上、私たちは袖を引っ張ってやりましょう.そこで、ネット上でいくつかの方法を探しました.主な考え方はこのようにいくつかあります.
  • ジャンプブラウザダウンロード
  • 使用システムのダウンロードサービス
  • カスタムダウンロードタスク
  • 考えがあればやりやすいので、具体的な実現を紹介します.WebViewがダウンロードをサポートするには、WebViewにダウンロードリスナーsetDownloadListenerを設定する必要があります.DownloadListenerにはonDownloadStartという方法しかありません.ファイルがダウンロードする必要があるたびに、この方法はコールバックされ、ダウンロードしたURLはメソッドパラメータを通じて伝達され、ダウンロードイベントをここで処理することができます.
    mWebView.setDownloadListener(new DownloadListener() {
        @Override
        public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
            // TODO: 2017-5-6       
        }
    });
    

    1.ブラウザからのダウンロード
    この方法は最も簡単で乱暴で、直接ダウンロードの任務をブラウザに投げて、残りは私たちが管理する必要はありません.欠点はダウンロード完了を感知できないことであり、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.システムを利用したダウンロードサービス
    DownloadManagerはシステムが提供するダウンロード処理のためのサービスで、利用者はダウンロードURIとストレージパスを提供し、簡単な設定を行うだけです.DownloadManagerはバックグラウンドでダウンロードを行い、ダウンロードに失敗した場合、ネットワークの切り替え、システムの再起動後に再ダウンロードを試みます.
         private void downloadBySystem(String url, String contentDisposition, String mimeType) {
            //       
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
            //       ,              、      
            request.allowScanningByMediaScanner();
            //          ,             
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            //         ,     ,       
    //        request.setTitle("This is title");
            //         
    //        request.setDescription("This is description");
            //           
            request.setAllowedOverMetered(false);
            //               
            request.setVisibleInDownloadsUi(false);
            //        
            request.setAllowedOverRoaming(true);
            //          
            request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
            //                
            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);
            //         
            long downloadId = downloadManager.enqueue(request);
            log.debug("downloadId:{}", downloadId);
        }
    

    これでダウンロードタスクを追加し、システムのダウンロードが完了するのを静かに待ちましょう.また、読み取りと書き込みの外部ストレージ権限とネットワーク権限を追加することを忘れないでください.では、ファイルのダウンロードに成功したことをどのように知っていますか.ダウンロードが完了すると、タスクIDが入ったブロードキャストが送信され、呼び出し元にタスクが完了したことを伝え、DownloadManagerでファイル情報を取得すればさらに処理できます.
        private class DownloadCompleteReceiver extends BroadcastReceiver {
    
            @Override
            public void onReceive(Context context, Intent intent) {
                log.verbose("onReceive. intent:{}", intent != null ? intent.toUri(0) : null);
                if (intent != null) {
                    if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
                        long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
                        log.debug("downloadId:{}", downloadId);
                        DownloadManager downloadManager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
                        String type = downloadManager.getMimeTypeForDownloadedFile(downloadId);
                        log.debug("getMimeTypeForDownloadedFile:{}", type);
                        if (TextUtils.isEmpty(type)) {
                            type = "*/*";
                        }
                        Uri uri = downloadManager.getUriForDownloadedFile(downloadId);
                        log.debug("UriForDownloadedFile:{}", uri);
                        if (uri != null) {
                            Intent handlerIntent = new Intent(Intent.ACTION_VIEW);
                            handlerIntent.setDataAndType(uri, type);
                            context.startActivity(handlerIntent);
                        }
                    }
                }
            }
        }
    
            //   
            DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
            registerReceiver(receiver, intentFilter);
    

    Ok、ここまで、システムサービスを利用してダウンロードが終わっても、簡単にまとめます.私たちは開始と完了だけに関心を持っています.ダウンロード中の一時停止、再試行などのメカニズムについては、システムが私たちを助けてくれました.とても友好的ではありませんか.
    3.カスタムダウンロードタスク
    ダウンロードリンクがあれば、自分でネットワーク部分を実現することができます.私はここでダウンロードタスクをカスタマイズしました.HttpURLConnectionとAsyncTaskを使って実現しましたが、コードは簡単です.
        private class DownloadTask extends AsyncTask<String, Void, Void> {
            //       :URL       
            private String url;
            private String destPath;
    
            @Override
            protected void onPreExecute() {
                log.info("    ");
            }
    
            @Override
            protected 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;
            }
    
            @Override
            protected 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() {
                @Override
                public 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);
                }
            });
    

    利点は、ダウンロードの進捗状況を感知し、開始、キャンセル、失敗、完了などのイベントを処理することであり、不足点はダウンロードの制御がシステムサービスに及ばず、自分でネットワークによる問題を処理しなければならないことである.