Android - 在 webview 中加载 PDF

Posted

技术标签:

【中文标题】Android - 在 webview 中加载 PDF【英文标题】:Android - Load PDF inside webview 【发布时间】:2012-05-18 04:47:34 【问题描述】:

我有这个 webview 代码,我希望在用户单击 PDF 链接时打开 PDF 文件。这是代码,你能告诉我我必须在这个PDF区域内放什么吗?我尝试了许多不同的方法,但根本无法查看 PDF。感谢您的帮助。

webview.setWebViewClient ( new WebViewClient() 
    public boolean shouldOverrideUrlLoading(WebView view, String url) 
        // do your handling codes here, which url is the requested url
        // probably you need to open that url rather than redirect:
        if (url.startsWith("tel:")) 
            startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
         else if (url.startsWith("mailto:")) 
            url = url.replaceFirst("mailto:", "");
            url = url.trim();
            Intent i = new Intent(Intent.ACTION_SEND);
            i.setType("plain/text").putExtra(Intent.EXTRA_EMAIL,
                    new String[]url);
            startActivity(i);

         else if (url.startsWith("geo:")) 
            try 
             catch (Exception e) 
                System.out.println(e);
            

         else if (url.endsWith("pdf")) 

            try 

             catch (Exception e) 
                System.out.println(e);
            

         else 
            view.loadUrl(url);
        
        return true;
        // then it is not handled by default action
    
);

【问题讨论】:

【参考方案1】:

这可能很简单:

try

 Intent intentUrl = new Intent(Intent.ACTION_VIEW);
 intentUrl.setDataAndType(url, "application/pdf");
 intentUrl.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 myActivity.startActivity(intentUrl);

catch (ActivityNotFoundException e)

 Toast.makeText(myActivity, "No PDF Viewer Installed", Toast.LENGTH_LONG).show();

虽然我没有尝试过。

在我们的应用程序中,我们将 PDF 下载到应用程序文件系统,使其可读,然后在 Intent 中传递路径以打开 PDF 查看应用程序(例如 Acrobat Reader)。请注意,您还需要清理这些下载的 PDF!

在你的 try 块中放

new DownloadPDFTask().execute(url);

下载PDFTask类:

public class DownloadPDFTask extends AsyncTask<String, Void, Integer> 

    protected ProgressDialog mWorkingDialog;    // progress dialog
    protected String mFileName;         // downloaded file
    protected String mError;            // for errors

    @Override
    protected Integer doInBackground(String... urls)
    

     try
     
      byte[] dataBuffer = new byte[4096];
          int nRead = 0;

          // set local filename to last part of URL
          String[] strURLParts = urls[0].split("/");
          if (strURLParts.length > 0)
            mFileName = strURLParts[strURLParts.length - 1];
          else
                mFileName = "REPORT.pdf";

          // download URL and store to strFileName

          // connection to url
      java.net.URL urlReport = new java.net.URL(urls[0]);
          URLConnection urlConn = urlReport.openConnection();
          InputStream streamInput = urlConn.getInputStream();
          BufferedInputStream bufferedStreamInput = new BufferedInputStream(streamInput);
          FileOutputStream outputStream = myActivity.openFileOutput(mFileName,Context.MODE_WORLD_READABLE); // must be world readable so external Intent can open!
          while ((nRead = bufferedStreamInput.read(dataBuffer)) > 0)
                outputStream.write(dataBuffer, 0, nRead);
          streamInput.close();
          outputStream.close();
      
      catch (Exception e)
      
       Log.e("myApp", e.getMessage());
       mError = e.getMessage();
       return (1);
      

     return (0);
    

    //-------------------------------------------------------------------------
    // PreExecute - UI thread setup
    //-------------------------------------------------------------------------

    @Override
    protected void onPreExecute()
    
     // show "Downloading, Please Wait" dialog
     mWorkingDialog = ProgressDialog.show(myActivity, "", "Downloading PDF Document, Please Wait...", true);
     return;
    

    //-------------------------------------------------------------------------
    // PostExecute - UI thread finish
    //-------------------------------------------------------------------------

    @Override
    protected void onPostExecute (Integer result)
    
         if (mWorkingDialog != null)
      
       mWorkingDialog.dismiss();
       mWorkingDialog = null;
      

         switch (result)
         
         case 0:                            // a URL

            // Intent to view download PDF
            Uri uri  = Uri.fromFile(myActivity.getFileStreamPath(mFileName));

            try
            
                Intent intentUrl = new Intent(Intent.ACTION_VIEW);
                intentUrl.setDataAndType(uri, "application/pdf");
                intentUrl.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                myActivity.startActivity(intentUrl);
            
            catch (ActivityNotFoundException e)
            
                Toast.makeText(myActivity, "No PDF Viewer Installed", Toast.LENGTH_LONG).show();
            

            break;

        case 1:                         // Error

            Toast.makeText(myActivity, mError, Toast.LENGTH_LONG).show();
            break;

        

    


任何对“myActivity”的引用都必须替换为对您的 Activity 类的引用

【讨论】:

是否可以在不运行异步下载任务的情况下仅从 web 视图中显示 PDF 文件? 不,与 ios 上的 UIWebView 不同,android WebView 不显示 PDF 内容。您可以尝试直接调用意图(即没有 AsyncDownloadTask),但无论如何您都会离开您的活动。 嗯,所以在 android 中最好的方法是调用 async 来下载文件并保存它。您知道该过程是否可以自动找到文件名并在SD卡上保存为该名称?我在使用它时总是指定名称。谢谢! 我会尝试将您的 http://file.pdf 网址交给意图,我认为 PDF 查看器程序(例如 Acrobat)会处理其余的事情。如果没有,下载器任务应该给你一个很好的起点。这部分代码处理文件命名,它从您的 URL 中提取文件名: // 将本地文件名设置为 URL 的最后一部分 String[] strURLParts = urls[0].split("/"); if (strURLParts.length > 0) mFileName = strURLParts[strURLParts.length - 1];否则 mFileName = "REPORT.pdf";【参考方案2】:

请在 webview 中查看处理重定向 url 和打开 PDF 而不下载的示例。

private void init()

    WebView webview = (WebView) findViewById(R.id.webview);
    WebSettings settings = webview.getSettings();
    settings.setjavascriptEnabled(true);
    webview.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);

    PdfWebViewClient pdfWebViewClient = new PdfWebViewClient(this, webview);
    pdfWebViewClient.loadPdfUrl(
                "https://www.google.co.in/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwjgwIfp3KXSAhXrhFQKHQqEDHYQFggZMAA&url=http%3A%2F%2Fwww.orimi.com%2Fpdf-test.pdf&usg=AFQjCNERYYcSfMLS5ukBcT2Qy11YxEhXqw&cad=rja");


private class PdfWebViewClient extends WebViewClient

    private static final String TAG = "PdfWebViewClient";
    private static final String PDF_EXTENSION = ".pdf";
    private static final String PDF_VIEWER_URL = "http://docs.google.com/gview?embedded=true&url=";

    private Context mContext;
    private WebView mWebView;
    private ProgressDialog mProgressDialog;
    private boolean isLoadingPdfUrl;

    public PdfWebViewClient(Context context, WebView webView)
    
        mContext = context;
        mWebView = webView;
        mWebView.setWebViewClient(this);
    

    public void loadPdfUrl(String url)
    
        mWebView.stopLoading();

        if (!TextUtils.isEmpty(url))
        
            isLoadingPdfUrl = isPdfUrl(url);
            if (isLoadingPdfUrl)
            
                mWebView.clearHistory();
            

            showProgressDialog();
        

        mWebView.loadUrl(url);
    

    @SuppressWarnings("deprecation")
    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String url)
    
        return shouldOverrideUrlLoading(url);
    

    @SuppressWarnings("deprecation")
    @Override
    public void onReceivedError(WebView webView, int errorCode, String description, String failingUrl)
    
        handleError(errorCode, description.toString(), failingUrl);
    

    @TargetApi(Build.VERSION_CODES.N)
    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request)
    
        final Uri uri = request.getUrl();
        return shouldOverrideUrlLoading(webView, uri.toString());
    

    @TargetApi(Build.VERSION_CODES.N)
    @Override
    public void onReceivedError(final WebView webView, final WebResourceRequest request, final WebResourceError error)
    
        final Uri uri = request.getUrl();
        handleError(error.getErrorCode(), error.getDescription().toString(), uri.toString());
    

    @Override
    public void onPageFinished(final WebView view, final String url)
    
        Log.i(TAG, "Finished loading. URL : " + url);
        dismissProgressDialog();
    

    private boolean shouldOverrideUrlLoading(final String url)
    
        Log.i(TAG, "shouldOverrideUrlLoading() URL : " + url);

        if (!isLoadingPdfUrl && isPdfUrl(url))
        
            mWebView.stopLoading();

            final String pdfUrl = PDF_VIEWER_URL + url;

            new Handler().postDelayed(new Runnable()
            
                @Override
                public void run()
                
                    loadPdfUrl(pdfUrl);
                
            , 300);

            return true;
        

        return false; // Load url in the webView itself
    

    private void handleError(final int errorCode, final String description, final String failingUrl)
    
        Log.e(TAG, "Error : " + errorCode + ", " + description + " URL : " + failingUrl);
    

    private void showProgressDialog()
    
        dismissProgressDialog();
        mProgressDialog = ProgressDialog.show(mContext, "", "Loading...");
    

    private void dismissProgressDialog()
    
        if (mProgressDialog != null && mProgressDialog.isShowing())
        
            mProgressDialog.dismiss();
            mProgressDialog = null;
        
    

    private boolean isPdfUrl(String url)
    
        if (!TextUtils.isEmpty(url))
        
            url = url.trim();
            int lastIndex = url.toLowerCase().lastIndexOf(PDF_EXTENSION);
            if (lastIndex != -1)
            
                return url.substring(lastIndex).equalsIgnoreCase(PDF_EXTENSION);
            
        
        return false;
    

【讨论】:

【参考方案3】:

我试图处理这种完全相同的情况。我想出的解决方案如下。

public boolean shouldOverrideUrlLoading(WebView view, String url) 
            String cleanUrl = url;
            if (url.contains("?")) 
                // remove the query string
                cleanUrl = url.substring(0,url.indexOf("?"));
            

            if (cleanUrl.endsWith("pdf")) 

                try 
                    Uri uriUrl = Uri.parse(cleanUrl);
                    Intent intentUrl = new Intent(Intent.ACTION_VIEW, uriUrl);
                    startActivity(intentUrl);
                    return true;

                 catch (Exception e) 
                    System.out.println(e);
                    Toast.makeText(context,"No PDF Viewer Installed", Toast.LENGTH_LONG).show();
                
            

            return false;
        

我需要确保它能够处理 pdf 链接,即使有查询字符串。由于 cleanUrl 需要以“pdf”结尾,因此仍然有点麻烦,但只要这是真的,这应该可以工作。如果您通过 php 脚本或其他方式提供 pdf,您可能需要更深入地挖掘,根据 MIME 类型或其他方式处理事情。

【讨论】:

【参考方案4】:

在 webview 中加载 pdf:

WebView wv = (WebView) view.findViewById(R.id.webPage);
            wv.getSettings().setJavaScriptEnabled(true);
            wv.setWebViewClient(new WebClient());
            wv.loadUrl("http://drive.google.com/viewerng/viewer?embedded=true&url=" + mUrl);
            wv.getSettings().setBuiltInZoomControls(true);

mUrl - 将成为您的 pdf 链接

【讨论】:

【参考方案5】:

FWIW,mozilla 有一个PDF-reader-entirely-in-JavaScript,它是 apache 许可的。如果您不介意额外的尺寸,可能值得研究。这样您就可以在浏览器中完成所有操作,而不必依赖第三方 PDF 阅读器。

【讨论】:

以上是关于Android - 在 webview 中加载 PDF的主要内容,如果未能解决你的问题,请参考以下文章

WebView在android中加载缓慢?

Android - 在 webview 中加载 PDF

取消在 Android 上的 WebView 中加载

Android Webview 不会在 webview 中加载我的 FPDF 链接

如何使用 Android Kotlin 在 WebView 中加载 URL?

特定的 webview 不会在 Android 的布局中加载