使用 Xamarin Forms 打开 PDF

2023-12-21

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

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

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

Device.OpenUri("file:///android_asset/filename.pdf");

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

有任何想法吗?


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

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

public interface IDocumentView
{
    void DocumentView(string file, string title);
}

Android

现在在你的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();
        }
    }
}
}

请注意,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>

此外,您还需要确保目标设备上安装了能够处理相关文件的应用程序。 (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;
    }
}
}

终于可以打电话了

DependencyService.Get<IDocumentView>().DocumentView(file.path, "Title of the view"); 

显示有问题的文件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Xamarin Forms 打开 PDF 的相关文章

  • 进程何时获得 SIGABRT(信号 6)?

    C 中进程获得 SIGABRT 的场景有哪些 该信号是否始终来自进程内部 或者该信号可以从一个进程发送到另一个进程吗 有没有办法识别哪个进程正在发送该信号 abort 向调用进程发送SIGABRT信号 就是这样abort 基本上有效 abo
  • 为什么libc++的shared_ptr实现使用完整内存屏障而不是宽松内存屏障?

    在boost的实现中shared ptr 它用放松内存排序以增加其引用计数 https github com boostorg smart ptr blob master include boost smart ptr detail sp
  • 迭代变量并查找特定类型实例的技术

    我想迭代进程中内存中的变量 通过插件动态加载 并查找特定类型的实例 以前我可以找到特定类型 或内存中的所有类型 我可以创建类型的实例 我可以获取作为不同类型的字段包含的实例 但我无论如何都不知道只是 搜索 特定类型的实例 一种方法是使用 W
  • 如何创建可以像 UserControl 一样编辑的 TabPage 子类?

    我想创建一个包含一些控件的 TabPage 子类 并且我想通过设计器来控制这些控件的布局和属性 但是 如果我在设计器中打开子类 我将无法像在 UserControl 上那样定位它们 我不想创建一个带有 UserControl 实例的 Tab
  • 使用浮动版本分发 NuGet 包的正确方法

    我正在创建一个依赖于 Xamarin Forms 的 NuGet 包 该包应该可以与任何最新版本的 Forms 一起正常工作 因此我将其设置为
  • 为什么要序列化对象需要 Serialized 属性

    根据我的理解 SerializedAttribute 不提供编译时检查 因为它都是在运行时完成的 如果是这样 那么为什么需要将类标记为可序列化呢 难道序列化器不能尝试序列化一个对象然后失败吗 这不就是它现在所做的吗 当某些东西被标记时 它会
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • 对齐 GridView 中的行值

    我需要在 asp net 3 5 中右对齐 gridview 列中的值 我怎样才能做到这一点
  • JSON 数组到 C# 列表

    如何将这个简单的 JSON 字符串反序列化为 C 中的列表 on4ThnU7 n71YZYVKD CVfSpM2W 10kQotV 这样 List
  • 暂停下载线程

    我正在用 C 编写一个非常简单的批量下载程序 该程序读取要下载的 URL 的 txt 文件 我已经设置了一个全局线程和委托来更新 GUI 按下 开始 按钮即可创建并启动该线程 我想要做的是有一个 暂停 按钮 使我能够暂停下载 直到点击 恢复
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • 检查算术运算中的溢出情况[重复]

    这个问题在这里已经有答案了 可能的重复 检测 C C 中整数溢出的最佳方法 https stackoverflow com questions 199333 best way to detect integer overflow in c
  • 如何从网站下载 .EXE 文件?

    我正在编写一个应用程序 需要从网站下载 exe 文件 我正在使用 Visual Studio Express 2008 我正在使用以下代码 private void button1 Click object sender EventArgs
  • 如何将“外部模板”与由同一类中的模板化成员使用的嵌套类一起使用?

    首先 一些背景信息 我尝试以 Herb Sutter 在他的解决方案中介绍的方式使用 Pimpl 习语 得到了 101 http herbsutter com gotw 101 这在头文件中看起来像这样 include pimpl h h
  • 通过 NHibernate 进行查询,无需 N+1 - 包含示例

    我有一个 N 1 问题 我不知道如何解决它 可以在这个问题的底部找到完全可重复的样本 因此 如果您愿意 请创建数据库 设置 NUnit 测试和所有附带的类 并尝试在本地消除 N 1 这是我遇到的真实问题的匿名版本 众所周知 这段代码对于帮助
  • g++ 对于看似不相关的变量“警告:迭代...调用未定义的行为”

    考虑以下代码strange cpp include
  • 将代码拆分为标头/源文件

    我从 Asio 的示例页面中获取了以下代码 class tcp connection public boost enable shared from this
  • 在类的所有方法之前运行一个方法

    在 C 3 或 4 中可以做到这一点吗 也许有一些反思 class Magic RunBeforeAll public void BaseMethod runs BaseMethod before being executed public
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化
  • 结构体指针的动态数组

    我必须使用以下代码块来完成学校作业 严格不进行任何修改 typedef struct char firstName char lastName int id float mark pStudentRecord pStudentRecord

随机推荐

  • TotalResults 计数与 YouTube v3 搜索 API 返回的实际结果不匹配

    我们正在使用 youtube v3 搜索 API 我们发现 totalResults 计数与response items 字段中返回的项目列表不匹配 我在请求中请求 50 个视频 返回的响应显示 TotalResults 计数为 65 但响
  • 请解释一下 Amazon RDS/Mysql 中的这种内存消耗模式?

    Folks 有人可以解释运行 Mysql 的 Amazon RDS 上的这种内存消耗模式吗 在此图中 我在 03 30 升级到了 db m2 2xlarge 具有 34GB 可用内存 您可以非常清楚地看到切换 当客户端开始连接并访问该实例时
  • 空间数据类型(几何)到 GeoJSON

    我想转换geom geometry 数据类型转换为 GeoJSON 我怎么能这么做呢 例如 WKT 中的几何图形 POLYGON 455216 346127297 4288433 28426224 455203 386722146 4288
  • 在 Groovy 中动态添加元素到 ArrayList

    我是 Groovy 的新手 尽管阅读了很多有关此的文章和问题 但我仍然不清楚发生了什么 据我目前的了解 当您在 Groovy 中创建一个新数组时 底层类型是 Java ArrayList 这意味着它应该是可调整大小的 您应该能够将其初始化为
  • 如何防止遗传算法收敛于局部极小值?

    我正在尝试使用遗传算法构建 4 x 4 数独求解器 我对值收敛到局部最小值有一些问题 我正在使用排名方法并删除排名底部的两个答案可能性 并将它们替换为排名最高的两个答案可能性之间的交叉 为了获得避免局部最小值的额外帮助 我还使用了突变 如果
  • 文字字符串 [Lua 5.1]

    所以我开始学习Lua 5 1 我看到了一个叫做文字字符串的东西 我不知道这些是做什么的 手册上说 a 是一个铃声 但是当我输入时 print hello athere IDE 打印一个奇怪的正方形 上面写着 bel 因此 如果有人可以帮助我
  • 为什么结构标签不是 C 中的类型名称? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 有人知道一个好的 MSI 日志查看器吗?

    相当简单的问题 有谁知道浏览 msi 日志文件的好实用程序吗 对任何提供过滤 不同标准和自定义操作 操作排序 属性和错误的良好视图的事物感兴趣 Thanks I found Rob Mensching 关于在 MSI 日志中查找的第一件事的
  • 如何使用 ReactJS 在 CKEditor 5 中使用 MathType 插件?

    我已经安装了三个包 ckeditor ckeditor5 react ckeditor ckeditor5 build classic wiris mathtype ckeditor5 src plugin 我可以设置简单的 ckedito
  • 如何优化具有数千个 WHERE 子句的 SQL 查询

    我对一个非常大的数据库进行了一系列查询 并且 WHERE 子句中有数十万个 OR 优化此类 SQL 查询的最佳且最简单的方法是什么 我找到了一些有关创建临时表和使用联接的文章 但我不确定 我是严肃 SQL 的新手 并且一直在将结果从一个SQ
  • iOS 15+ contextMenu 中的反向 ScrollView 错误

    感谢您花时间帮助他人 例如 我已经检查了所有解决方案这个帖子 https stackoverflow com questions 61726424 swiftui chat app the woes of reversed list and
  • 泛型:为什么编译器在这种情况下无法推断类型参数?

    我想编写一个扩展方法 该方法适用于其值是某种序列的字典 不幸的是 编译器似乎无法从我对该方法的使用中推断出通用参数 我需要明确指定它们 public static void SomeMethod
  • 找不到模块 java.xml.bind

    我是新来的javafx和日食 我从 eclipse market 安装了 eclipse 然后 javafx 我使用场景生成器生成了 fxml 代码 但无法执行它 我真的很受阻 找不到任何解决方案 I added add modules j
  • jQuery Datatables - 从其他页面检索信息

    我在从 jQuery 数据表获取信息时遇到问题 这是表格 我想获取表中存储的信息 我尝试通过以下方式做到这一点 var languages var people select name languageID each function la
  • 确定 WindowsIdentity 实例的嵌套组

    假设我有一个实例WindowsIdentity并想要获取它所属的组 我使用以下代码来获取列表 WindowsIdentity identity null get identity here identity Groups Translate
  • 检测到零个或 2 个或多个 [DropdownMenuItem] 具有相同的值

    我是 Flutter 新手 但我正在尝试创建一个 DropdownButtonFormField 但它不起作用 我收到一条错误消息 提示我有重复的值 有趣的是 我没有包含重复值的列表 我在 SO 上发现了一个类似的问题 解决方案说用一个值启
  • 在 Eclipse 中,我可以同时拥有多个控制台视图,每个视图显示不同的控制台吗?

    我正在开发一些在调试模式下记录到控制台的应用程序 我想从 Eclipse 内部运行和调试它们 并同时查看每个的控制台 但是 我有一个控制台选项卡 一次显示一个控制台输出 有没有办法可以将控制台拆分为多个视图 以便可以并排控制台输出 Yes
  • 以 Rails 4 形式将

    我有一个 Rails 4 表单 它在表单页面上使用 AJAX 构建部件列表 一旦零件清单建立在 ul 我想将列表作为 params 哈希中的参数值数组提交 My form div h2 prohibited this service fro
  • 如何使用下载链接从 Azure Blob 存储下载文件

    我制作了一个 Azure 云服务 您可以在其中使用 Blob 将文件上传和删除到云存储 我成功编写了一个方法 您可以从云服务中删除上传的 blob public string DeleteImage string Name Uri uri
  • 使用 Xamarin Forms 打开 PDF

    我有一个 pdf 文件 已使用 xamarin 表单添加为 Android 和 IOS 项目的 AndroidAsset 和 BundleResource 我只是希望能够使用设备默认的任何 pdf 查看器从任何设备打开这些文件 本质上 我只