在 WebView 问题中查看 PDF (Xamarin.ios)

Posted

技术标签:

【中文标题】在 WebView 问题中查看 PDF (Xamarin.ios)【英文标题】:View a PDF in WebView Issue (Xamarin.ios) 【发布时间】:2018-11-03 20:52:08 【问题描述】:

我目前在将本地 pdf 加载到 webview 时遇到问题。我的代码没有任何错误,当我在 iPad 模拟器上运行它时,它绝对完美。但是,当我尝试在物理 iPad 设备上运行它时,问题就出现了。当我运行它并到达需要显示 PDF 的地步时,webview 会加载,但 webview 中没有显示 PDF。

PDF 实际上是由应用程序生成的,我将它存储在库文件夹内的目录中。

在 WebView 中显示 PDF 的代码:

public void LoadPdfToWebView(string pdfPath)
    
        //Console.WriteLine("Load request started");

        WebView.LoadRequest(new NSUrlRequest(new NSUrl(pdfPath, false)));
        View.AddSubview(WebView);

        //Console.WriteLine("Load request Finished");
    

不太清楚为什么会这样,希望有人可以提供帮助。

【问题讨论】:

【参考方案1】:

在 Xamarin.ios 中在 UIWebView 中显示 html 以外的文档类型:

    将文档(例如 PDF)添加到 Xamarin.iOS 项目。将构建操作设置为 BundleResource。您可以通过右键单击该文件并在打开的菜单中选择构建操作来设置文件的构建操作。

    创建一个 UIWebView 并将其添加到视图中:

    webView = new UIWebView (View.Bounds);
    View.AddSubview(webView);
    

    使用 NSUrl 和 NSUrlRequest 类加载文件:

    string fileName = "Loading a Web Page.pdf"; // remember case-sensitive
    string localDocUrl = Path.Combine (NSBundle.MainBundle.BundlePath, fileName);
    webView.LoadRequest(new NSUrlRequest(new NSUrl(localDocUrl, false)));
    webView.ScalesPageToFit = true;
    

您可以参考这个官方步骤。如果有问题或其他需要,可以参考this link

如果无法读取bundle中的资源,可以将资源缓存放在沙盒的temp目录下,尝试使用LoadRequest读取。

【讨论】:

@johnheacen 感谢您的回复。我遇到的问题是 PDF 实际上是在应用程序内部创建的,并被添加到库文件夹中。这意味着我无法将其物理添加到捆绑资源中。加载请求已经指向这个动态创建的 PDF 文件。这很奇怪,因为它在模拟器上运行良好,但在物理设备上运行良好? 我建议您在物理设备上运行时可以打印pdfPath。然后我们可以找到更多信息。 如果无法读取bundle中的资源,可以将资源缓存放在沙盒的temp目录下,尝试使用LoadRequest读取。 感谢您的建议,但我最终使用的是 Syncfusion pdf 查看器而不是 WebView【参考方案2】:

我刚刚为一个应用解决了这个问题,并认为我会发布解决方案

这是针对 WKWebView 的,这是 Apple 自 2020 年 12 月以来的要求,尽管截止日期已暂时延长

Xaml PdfWebView 内容页面

<controls:PdfWebView
  Source="Binding PDFSource"
  HeightRequest="1000"
  WidthRequest="1000"/>

控制

namespace XForms.Controls

    public class PdfWebView : WebView  

VM,只有相关部分

private string _pdfSource;
public string PDFSource

      get => _pdfSource;
      set
      
           if (Device.RuntimePlatform == Device.android && value.StartsWith("file:") == false)
           
                value = $"file:///android_asset/pdfjs/web/viewer.html?file=file:///WebUtility.UrlEncode(value)";
           
           SetProperty(ref _pdfSource, value);
      

PdfWebView 的 iOS 渲染器

using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using XForms.Controls;
using WebKit;
using Foundation;

[assembly: ExportRenderer(typeof(PdfWebView), typeof(iOSUI.Renderers.PdfWebViewRenderer))]
namespace iOSUI.Renderers

    public class PdfWebViewRenderer : ViewRenderer<WebView, WKWebView>
    
        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        
            base.OnElementChanged(e);

            if (Control == null)
            
                var wkWebViewConfiguration = new WKWebViewConfiguration();

                var wkWebView = new WKWebView(Frame, wkWebViewConfiguration)
                
                    AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
                ;
                SetNativeControl(wkWebView);
            
            if (e.NewElement != null)
            
                if (string.IsNullOrEmpty(((UrlWebViewSource)e.NewElement.Source)?.Url) == false)
                
                    var url = ((UrlWebViewSource)e.NewElement.Source).Url;
                    if(url.StartsWith("http"))
                    
                        Control.LoadRequest(new NSUrlRequest(new NSUrl(url)));
                    
                    else
                    
                        Control.LoadFileUrl(new NSUrl($"file://url"), new NSUrl($"file://url"));
                    
                
            
        
    

Android 渲染器

using System.Net;
using Android.Content;
using Android.Views;
using Android.Webkit;
using XForms.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(PdfWebView), typeof(AndroidUI.Renderers.PDFViewRenderer))]
namespace AndroidUI.Renderers

    public class PDFViewRenderer : WebViewRenderer
    
        public PDFViewRenderer(Context context) : base(context)  

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        
            base.OnElementChanged(e);

            if (e.NewElement != null)
            
                Control.Settings.javascriptEnabled = true;
                Control.Settings.DomStorageEnabled = true;
                Control.Settings.AllowFileAccess = true;
                Control.Settings.AllowFileAccessFromFileURLs = true;
                Control.Settings.AllowUniversalAccessFromFileURLs = true;

                Control.SetWebChromeClient(new WebChromeClient());
            
        

        // If you want to enable scrolling in WebView uncomment the following lines.
        public override bool DispatchTouchEvent(MotionEvent e)
        
            Parent.RequestDisallowInterceptTouchEvent(true);
            return base.DispatchTouchEvent(e);
        
    

此解决方案使用 Android 中的 pdfjs 和 iOS 中的 WKWebview 来呈现 PDF

PDFSource 是文件的完整路径,我使用 System.IO .net 标准调用以跨平台方式处理此问题

所有文件都存放在里面(我有个方法叫GetFullPath返回跨平台公共路径)

Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)

通过 Path.Combine 与文件名结合

Path.Combine(GetFullPath(), fileName);

这是在 VM 中设置的 PDFSource

Pdfjs 库文件只是复制到 Assets/pdfjs for Android

iOS 的神奇之处在于调用 LoadFileUrl 而不是 LoadRequest 并在前面加上“file://”

我已经稍微清理了我们的命名空间,因此其中一些不会像 XForms.Controls 等引用我们的内部代码那样解析

【讨论】:

以上是关于在 WebView 问题中查看 PDF (Xamarin.ios)的主要内容,如果未能解决你的问题,请参考以下文章

查看pdf时隐藏或修改Webview2的工具栏

Android - 在 webview 中加载 PDF

ios滚动webview以在pdf中添加书签

PDF 到 html 和 webview

UWP 发送文件数据到 WebView

如何显示包含 pdf 的 url 并将其显示在 Webview Android Java 中