如何在安装文件夹外的 xamarin pcl uwp 中显示 pdf 文件?

How can I show an pdf file in xamarin pcl uwp that is outside my instal folder?

嗨,我正在 Xamarin PCL 项目中使用平台 AndroidUWP。作为一项功能,用户应该能够打开 pdf 文件。

为此,我使用 Mozilla pdf.js。我按照这个 link 在 Android 和 UWP 上完成了它。 https://developer.xamarin.com/recipes/cross-platform/xamarin-forms/controls/display-pdf/ 仅适用于 UWP 我无法使其运行。

这是我的 UWP 自定义渲染器

[assembly: ExportRenderer(typeof(PdfView), 
typeof(PDF.UWP.Renderers.PdfViewRenderer))]
namespace PDF.UWP.Renderers
{
/// <summary>
/// The asset folder of the UWP app must contain the pdfjs folder and files.
/// </summary>
public class PdfViewRenderer: WebViewRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
    {
        base.OnElementChanged(e);
        if (e.NewElement != null)
        {
            PdfView pdfView = Element as PdfView;
            string sFile = string.Format("ms-appx-web://{0}", WebUtility.UrlEncode(pdfView.Uri));
            Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));
        }
    }
}
}

这是我的 PdfView class.

public class PdfView: WebView
{
    public static readonly BindableProperty DocumentInfoProperty =
        BindableProperty.Create(propertyName: nameof(TheDocumentInfo), returnType: typeof(DocumentInfo),
            declaringType: typeof(PdfView), defaultValue: default(DocumentInfo));

    public DocumentInfo TheDocumentInfo
    {
        get { return (DocumentInfo)GetValue(DocumentInfoProperty); }
        set { SetValue(DocumentInfoProperty, value); }
    }

    public string Uri { get { return TheDocumentInfo.LocalUrl; } }
    public string FileName { get { return TheDocumentInfo.FileName; } }
}

The file location on uwp = "ms-appx-web://C%3A%5CUsers%5CUser%5CAppData%5CLocal%5CPackages%5CPDFTEST.UWP_v4j5n0js0cwst%5CLocalState%5CPDFTest.pdf"

这是正确的。

但是错误是:

Message: Unexpected server response (0) while retrieving PDF "ms-appx-web://C:/Users/User/AppData/Local/Packages/PDFTest.UWP_v4j5n0js0cwst/LocalState/PDFTest.pdf/".

更新

我已将渲染器重新创建为:

protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
    {
        base.OnElementChanged(e);
        if (e.NewElement != null)
        {
            // TODO: testen
            PdfView pdfView = Element as PdfView;
            string sFile = string.Format("ms-appx-web://{0}/{1}", pdfView.Uri.Replace(pdfView.FileName, ""), WebUtility.UrlEncode(pdfView.FileName));
            Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));
        }
    }

我不知道这是否是我的问题的解决方案,但此错误已消失。 现在的错误是:

PDF.js v1.1.366 (build: 9e9df56)

Message: stream must have data

更新(我不知道你是否应该在这个问题中添加这个或者我是否应该再做一个)。

我的错误还是

stream must have data

我现在知道为什么了。因为我正在开发 UWP 应用程序并且我想访问安装文件夹之外的文件。这个位置是

C:\Users\User\AppData\Local\Packages\PDFTest.UWP_v4j5n0js0cwst\LocalState\

显然我无法访问安装文件夹之外的文件。这包括将文件复制到我的安装文件夹并在那里阅读。

更新 我的项目中有 2 个版本的 pdf.js。 (1.1.366 和 1.9.426) 这是我现在的代码

    protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
    {
        base.OnElementChanged(e);
        if (e.NewElement != null)
        {
            PdfView pdfView = Element as PdfView;
            var uriString = "ms-appdata:///local/" + WebUtility.UrlEncode(pdfView.FileName);
            Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", uriString));
        }
    }

当我尝试使用 Launcher.LaunchFileAsync 打开文件并使用 uriString 时,它会打开我的浏览器并显示文件。

在我的应用程序中出现以下错误

(v1.1.366) Stream must have data.

(v1.9.426) Unexpected server response (0) while retrieving PDF "ms-appdata:///local/PDFTest.pdf".

我知道 pdf uri 是正确且可访问的,但它仍然不起作用。 (对于 v1.9.426,我在 viewer.js

中添加了

var HOSTED_VIEWER_ORIGINS = ['null', 'http://mozilla.github.io', 'https://mozilla.github.io', 'ms-appdata://', 'ms-appx-web://PDFTest.uwp'];)

link to the testproject

I know now why. Because I'm developing a UWP application and I want to access a file outside my instal folder. This location is

您已使用 ms-appx-web: uri 方案作为您的 pdf 文件访问路径。实际上,您的 pdf 路径是存储在应用程序本地文件夹中的 C:\Users\User\AppData\Local\Packages\PDFTest.UWP_v4j5n0js0cwst\LocalState\。所以文件不会被访问。

我还测试了 "ms-appdata:///local/" uri 方案以访问基于您项目的 pdf 文件。不幸的是,它无法被 viewer.js 识别。

然后,我尝试将 pdf 文件转换为 Base64String,然后通过调用 viewer.js.

中的 openPdfAsBase64 JS 函数打开它
private async Task<string> OpenAndConvert(string FileName) 
{
    var folder = ApplicationData.Current.LocalFolder;
    var file = await folder.GetFileAsync(FileName);
    var filebuffer = await file.OpenAsync(FileAccessMode.Read);
    var reader = new DataReader(filebuffer.GetInputStreamAt(0));
    var bytes = new byte[filebuffer.Size];
    await reader.LoadAsync((uint)filebuffer.Size);
    reader.ReadBytes(bytes);
    return Convert.ToBase64String(bytes);  
}

用法

protected  override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
    base.OnElementChanged(e);
    if (e.NewElement != null)
    {   
        Control.Source = new Uri("ms-appx-web:///Assets/pdfjs3/web/viewer.html");
        Control.LoadCompleted += Control_LoadCompleted;
    }
}

private async void Control_LoadCompleted(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
    CustomWebView pdfView = Element as CustomWebView;
    if (string.IsNullOrEmpty(pdfView?.Filename)) return;

    var ret = await OpenAndConvert(pdfView?.Filename);       

    var obj = await Control.InvokeScriptAsync("openPdfAsBase64", new[] { ret });
}

您可以使用这个 viewer.js 添加的 openPdfAsBase64 方法。

得到以下提示How to embed the PDFjs into your C# Project