El0din
El0din

Reputation: 3370

Open local pdf file in Xamarin Forms

i'm triying to open a local pdf file in xamarin forms, my code:

var context = Forms.Context;
Java.IO.File javaFile = new Java.IO.File(filePath);
Android.Net.Uri uri = FileProvider.GetUriForFile(context, "myAuth.fileprovider", javaFile);
context.GrantUriPermission(context.PackageName, uri, ActivityFlags.GrantReadUriPermission);                        
Intent intent = new Intent(Intent.ActionView);
intent.SetDataAndType(uri, "application/pdf");
intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
Xamarin.Forms.Forms.Context.StartActivity(intent);

i followed several tutorials like this: How to get actual path from Uri xamarin android

But now my problem is that i don't know if the uri is getting the real path for the file:

i got this :

javaFile = "/storage/emulated/0/Download/myReport.pdf" (checked and exist)

uri = "content://myAuth.fileprovider/external_files/Download/myReport.pdf"

But i got this error on my pdf app "this file cannot be accessed". What i need to change to take the real path of the file? i think the problem is here:

Android.Net.Uri uri = FileProvider.GetUriForFile(context, "myAuth.fileprovider", javaFile);

But don't know what more change in order to work. Thx a lot!

Upvotes: 0

Views: 1606

Answers (2)

El0din
El0din

Reputation: 3370

If someone has follow the steps before and still does not works, and the problem continues in the line var uri = FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".fileprovider", file);. Check this too:

1 - Check if it's into Application tag

2 - Check the autority, usually you will use "${applicationId}.provider", but if not works, use a literal, for example myAuth.fileprovider

<application>
...
    <provider ..android:authorities="myAuth.fileprovider" ..>
        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data>
    </provider>
</application>

3 - Check the context, var context = Android.App.Application.Context; it's the usually, but if this one does not works, you can try MainActivity.Current, but you need to create first a static var into the MainActivity Class, something like this: public static MainActivity Current = null; and initialize into the OnCreate Method Current = this;. That's was my problem

4 - Check the type of the MimeType of the data, intent.SetDataAndType(uri, "application/pdf");

Thanks again to Leon Lu - MSFT for the answer, this is just an extension for anyone facing the same problem as me.

Upvotes: 0

Leon Lu
Leon Lu

Reputation: 9274

You should set the FileProvider in the application tag of AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.boxviewcolordemo" android:installLocation="auto">
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
    <application android:label="BoxViewColorDemo.Android">

    <provider android:name="android.support.v4.content.FileProvider"
          android:authorities="${applicationId}.fileprovider"
          android:exported="false"
          android:grantUriPermissions="true">

      <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                       android:resource="@xml/file_paths"></meta-data>
    </provider>
  </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</manifest>

Then create file_paths.xml in the xml folder.

enter image description here

file_paths.xml add following code.

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

Then in your dependenceService achievement, you should use following code. Note: FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".fileprovider", file); the second attribute is you package name and ".fileprovider"

[assembly: Dependency(typeof(OpenPDF))]
namespace BoxViewColorDemo.Droid
{
    public class OpenPDF : IOpenFile
    {
        public void OpenPDf(string filePath)
        {
            var rs = System.IO.File.Exists(filePath);
            if (rs)
            {
                var context = Android.App.Application.Context;
                var file = new Java.IO.File(filePath);

                var uri = FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName  + ".fileprovider", file);
                try
                {
                    var intent = new Intent(Intent.ActionView);
                    intent.AddCategory(Intent.CategoryDefault);
                    intent.AddFlags(ActivityFlags.GrantReadUriPermission);
           
                    intent.AddFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
                    intent.SetDataAndType(uri, "application/pdf");
                    context.StartActivity(intent);
                }
                catch (Exception e)
                {
                    Toast.MakeText(context, e.Message, ToastLength.Long).Show();
                }
            }
            
        }
    }
}

And do not forget to grand the read/write permission at the runtime. For testing, you can add following code to the OnCreate method of MainActivity.cs.

  if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != (int)Permission.Granted)
            {
                RequestPermissions(new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage }, 0);
            }

I put the pdf file to the Download folder, my filePath is DependencyService.Get<IOpenFile>().OpenPDf("/storage/emulated/0/Download/test.pdf");

enter image description here

Upvotes: 1

Related Questions