使用 Xamarin Forms 打开 PDF

mo *_*laz 0 c# mobile xamarin.forms

我有一个 pdf 文件,已使用 xamarin 表单添加为 Android 和 IOS 项目的 AndroidAsset 和 BundleResource。

我只是希望能够使用设备默认的任何 pdf 查看器从任何设备打开这些文件。

本质上,我只想能够做类似的事情:

Device.OpenUri("file:///android_asset/filename.pdf");
Run Code Online (Sandbox Code Playgroud)

但这似乎不起作用。没有任何反应,也不会提示用户打开 pdf 文件。我不想使用任何允许 pdf 在应用程序中打开的第三方库,我只是希望它将用户重定向到 pdf 查看器或浏览器。

有任何想法吗?

Mar*_*hel 5

首先,您需要一个接口类,因为您需要调用依赖项服务才能将文档传递给应用程序的本机实现:

因此,在您的共享代码中添加一个名为“IDocumentView.cs”的界面:

public interface IDocumentView
{
    void DocumentView(string file, string title);
}
Run Code Online (Sandbox Code Playgroud)

安卓

现在在你的android项目中创建相应的实现“DocumentView.cs”:

assembly: Dependency(typeof(DocumentView))]
namespace MyApp.Droid.Services
{
public class DocumentView: IDocumentView
{
    void IDocumentView.DocumentView(string filepath, string title)
    {
        try
        {
            File file = new File(filepath);

            String mime = FileTypes.GetMimeTypeByExtension(MimeTypeMap.GetFileExtensionFromUrl(filepath));
            File extFile = new File (Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDocuments), file.Name);
            File extDir = extFile.ParentFile;
            // Copy file to external storage to allow other apps to access ist
            if (System.IO.File.Exists(extFile.AbsolutePath))
                System.IO.File.Delete(extFile.AbsolutePath);

            System.IO.File.Copy(file.AbsolutePath, extFile.AbsolutePath);
            file.AbsolutePath, extFile.AbsolutePath);
            // if copying was successful, start Intent for opening this file
            if (System.IO.File.Exists(extFile.AbsolutePath))
            {
                Intent intent = new Intent();
                intent.SetAction(Android.Content.Intent.ActionView);
                intent.SetDataAndType(Android.Net.Uri.FromFile(extFile), mime);
                MainApplication.FormsContext.StartActivityForResult(intent, 10);
            }
        }
        catch (ActivityNotFoundException anfe)
        {
            // android could not find a suitable app for this file
            var alert = new AlertDialog.Builder(MainApplication.FormsContext);
            alert.SetTitle("Error");
            alert.SetMessage("No suitable app found to open this file");
            alert.SetCancelable(false);
            alert.SetPositiveButton("Okay", (object sender, DialogClickEventArgs e) => ((AlertDialog)sender).Hide());
            alert.Show();
        }
        catch (Exception ex)
        {
            // another exception
            var alert = new AlertDialog.Builder(MainApplication.FormsContext);
            alert.SetTitle("Error");
            alert.SetMessage("Error when opening document");
            alert.SetCancelable(false);
            alert.SetPositiveButton("Okay", (object sender, DialogClickEventArgs e) => ((AlertDialog)sender).Hide());
            alert.Show();
        }
    }
}
}
Run Code Online (Sandbox Code Playgroud)

请注意,MainApplication.FormsContext 是我添加到 MainApplication.cs 中的静态变量,以便能够快速访问应用程序的上下文。

在您的 Android 清单中,添加

在您的应用程序资源中,添加名为 file_paths.xml 的 xml 资源(到文件夹“xml”中),其中包含以下内容:

<paths xmlns:android="http://schemas.android.com/apk/res/android">
   <external-files-path name="root" path="/"/>
   <external-files-path name="files" path="files" />
</paths>
Run Code Online (Sandbox Code Playgroud)

此外,您还需要确保目标设备上安装了能够处理相关文件的应用程序。(Acrobat Reader、Word、Excel 等)。

iOS系统

iOS 已经内置了一个相当不错的文档预览,因此您可以简单地使用它(再次在您的 iOS 项目中创建一个名为“DocumentView.cs”的文件):

[assembly: Dependency(typeof(DocumentView))]
namespace MyApp.iOS.Services
{
public class DocumentView: IDocumentView
{
    void IDocumentView.DocumentView(string file, string title)
    {
        UIApplication.SharedApplication.InvokeOnMainThread(() =>
        {
            QLPreviewController previewController = new QLPreviewController();

            if (File.Exists(file))
            {
                previewController.DataSource = new PDFPreviewControllerDataSource(NSUrl.FromFilename(file), title);
                UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(previewController, true, null);
            }
        });
    }
}

public class PDFItem : QLPreviewItem
{
    public PDFItem(string title, NSUrl uri)
    {
        this.Title = title;
        this.Url = uri;
    }
    public string Title { get; set; }
    public NSUrl Url { get; set; }
    public override NSUrl ItemUrl { get { return Url; } }
    public override string ItemTitle { get { return Title; } }
}

public class PDFPreviewControllerDataSource : QLPreviewControllerDataSource
{
    PDFItem[] sources;

    public PDFPreviewControllerDataSource(NSUrl url, string filename)
    {
        sources = new PDFItem[1];
        sources[0] = new PDFItem(filename, url);
    }

    public override IQLPreviewItem GetPreviewItem(QLPreviewController controller, nint index)
    {
        int idx = int.Parse(index.ToString());
        if (idx < sources.Length)
            return sources.ElementAt(idx);
        return null;
    }

    public override nint PreviewItemCount(QLPreviewController controller)
    {
        return (nint)sources.Length;
    }
}
}
Run Code Online (Sandbox Code Playgroud)

终于可以打电话了

DependencyService.Get<IDocumentView>().DocumentView(file.path, "Title of the view"); 
Run Code Online (Sandbox Code Playgroud)

显示有问题的文件。