【问题标题】:Open pdf by 3rd party app in xamarin forms error 'Error when opening document'在 xamarin 表单中由 3rd 方应用程序打开 pdf 错误“打开文档时出错”
【发布时间】:2019-08-28 14:52:44
【问题描述】:

我正在尝试在 android 设备上的第 3 方应用程序中打开 pdf,但这是不可能的。该应用程序以共享项目的 xamarin 形式构建。我以这里提供的解决方案为基础:Opening a PDF with Xamarin Forms

//我把接口改成字节数组是因为我要下载pdf

public interface IDocumentView
{
    void DocumentView(byte[] bytes,string name, string title);
}

//在我的android项目中:

[assembly: Xamarin.Forms.Dependency(typeof(DocumentView))]
namespace FMSXMobileApp.Droid
{   
    public class DocumentView : IDocumentView
    {
        void IDocumentView.DocumentView(byte[] bytes, string name, string title)
        {
            var context = Xamarin.Forms.Forms.Context;

            try
            {   
                File extFile = new File(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads), 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.WriteAllBytes(extFile.AbsolutePath, bytes);
                String mime = MimeTypeMap.GetFileExtensionFromUrl(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);
                    context.ApplicationContext.StartActivity(intent);
                }
            }
            catch (ActivityNotFoundException anfe)
            {
                // android could not find a suitable app for this file
                var alert = new AlertDialog.Builder(context);
                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(context);
                alert.SetTitle("Error");
                alert.SetMessage("Error when opening document");
                alert.SetCancelable(false);
                alert.SetPositiveButton("Okay", (object sender, DialogClickEventArgs e) => ((AlertDialog)sender).Hide());
                alert.Show();
            }
        }
    }
}

//从我的 xamarin 表单共享项目中,我调用了下一条语句:

DependencyService.Get<IDocumentView>().DocumentView(doc.File, "test.pdf", "Title of the view");

//在我的android项目的xml文件夹中(file_paths.xml):

<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="root" path="/"/>
    <external-files-path name="files" path="files" />
</paths>

//在我添加的清单中:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.mydomain.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

应用程序在此行失败:

System.IO.File.WriteAllBytes(extFile.AbsolutePath, bytes);

但代码没有运行我收到错误消息:打开文档时出错。我究竟做错了什么?我正在使用 android 9.0 sdk 28。

这是堆栈跟踪:

System.UnauthorizedAccessException: Access to the path "/storage/emulated/0/Download/test.pdf" is denied.
  at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share, System.Int32 bufferSize, System.Boolean anonymous, System.IO.FileOptions options) [0x001b7] in <ff07eae8184a40a08e79049bbcb31a0e>:0 
  at System.IO.FileStream..ctor (System.String path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share) [0x00000] in <ff07eae8184a40a08e79049bbcb31a0e>:0 
  at (wrapper remoting-invoke-with-check) System.IO.FileStream..ctor(string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
  at System.IO.File.InternalWriteAllBytes (System.String path, System.Byte[] bytes) [0x00000] in <ff07eae8184a40a08e79049bbcb31a0e>:0 
  at System.IO.File.WriteAllBytes (System.String path, System.Byte[] bytes) [0x00039] in <ff07eae8184a40a08e79049bbcb31a0e>:0 
  at FMSXMobileApp.Droid.DocumentView.FMSXMobileApp.Interfaces.IDocumentView.DocumentView (System.Byte[] bytes, System.String name, System.String title) [0x0003d] in D:\FMSXAPP\FMSXMobileApp\FMSXMobileApp.Android\DocumentView.cs:28

【问题讨论】:

  • 能否请您发布此错误的完整日志?如果能分享一个基本的演示,我们可以用它进行测试?
  • 嗨,杰西,感谢您的回答。我很乐意创建一个演示,但我如何在这里分享演示?
  • @JessieZhang:我已经用异常的堆栈跟踪编辑了我的问题。

标签: c# .net xamarin.forms xamarin.android


【解决方案1】:

正如 CrazyTim 在https://stackoverflow.com/a/24796126/11992780 中回答的那样

有4种情况:

  • 调用者没有所需的权限。
  • 该文件是一个正在使用的可执行文件。
  • 路径是一个目录。
  • 路径指定了一个只读文件。

【讨论】:

  • 您好 Alex Sunder Singh,感谢您的回答。我查看了您给我的链接,但它没有说明有关 xamarin forms en android 的任何信息。我在作为 xamarin 表单应用程序构建的 android 应用程序中遇到问题。我已经猜到我没有权限,但问题是,我的代码有什么问题?我需要添加更多吗?我错过了什么?提前致谢
【解决方案2】:

我终于找到了适合我的解决方案。问题是我的应用程序需要请求访问存储。我将这个库用于请求https://www.nuget.org/packages/Plugin.Permissions/

这是我在documents.xaml 页面中的代码:

var status = await Utils.CheckPermissions(Permission.Storage);
if (status == PermissionStatus.Denied) return;
DependencyService.Get<IDocumentView>().DocumentView(doc.File, "test.pdf", "Title of the view");

在我的 .android 项目的 MainActivity 中,我必须添加以下代码:

 public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
        {
            PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
        }

这是我在 mij .android 项目中的新 DocumentView:

[assembly: Xamarin.Forms.Dependency(typeof(DocumentView))]
namespace FMSXMobileApp.Droid
{
    public class DocumentView : IDocumentView
    {
        void IDocumentView.DocumentView(byte[] bytes, string name, string title)
        {
            var context = Android.App.Application.Context;

            try
            {
                var filePath = CommonLibrary.Helpers.FileHelper.WriteFileFromByteArray(bytes, Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).Path, "fmsxapp.pdf");
                var mime = MimeTypeMap.GetFileExtensionFromUrl(filePath);
                // if copying was successful, start Intent for opening this file
                if (System.IO.File.Exists(filePath))
                {                    
                    Android.Net.Uri pdfPath = FileProvider.GetUriForFile(context, "com.mydomain.fileprovider", new Java.IO.File(filePath));
                    context.GrantUriPermission(context.PackageName, pdfPath, ActivityFlags.GrantReadUriPermission);
                    Intent intent = new Intent();
                    intent.SetFlags(ActivityFlags.GrantReadUriPermission);                    
                    intent.SetAction(Android.Content.Intent.ActionView);
                    intent.SetDataAndType(pdfPath, $"application/{mime}");
                    context.StartActivity(intent);
                }
            }
            catch (ActivityNotFoundException anfe)
            {
                // android could not find a suitable app for this file
                var alert = new AlertDialog.Builder(context);
                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(context);
                alert.SetTitle("Error");
                alert.SetMessage("Error when opening document");
                alert.SetCancelable(false);
                alert.SetPositiveButton("Okay", (object sender, DialogClickEventArgs e) => ((AlertDialog)sender).Hide());
                alert.Show();
            }
        }
    }
}

我没有更改清单文件中的任何内容。我确实更改了我的 file_paths.xml 文件:

<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <external-files-path name="root" path="."/>
  <external-files-path name="files" path="files" />
  <external-path name="external_files" path="."/>
</paths>

经过这种修改后,它就像一个魅力。我希望这可以帮助那些也在努力让它工作的人。

【讨论】:

    猜你喜欢
    • 2013-02-18
    • 1970-01-01
    • 2020-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-04
    相关资源
    最近更新 更多