2

I created a .pdf file in the private local directory I got via (I try to work with the minimum of permissions):

string targetBaseDir = Environment.GetFolderPath(
    Environment.SpecialFolder.Personal,
    Environment.SpecialFolderOption.Create
    );

The official Android documentation suggests that file should be shared via a FileProvider.

I also tried to get some code to start an intent, and I'm currently at:

var fileUri = Android.Net.Uri.Parse(filePath);

var intent = new Intent();
intent.SetFlags(ActivityFlags.ClearTop);
intent.SetFlags(ActivityFlags.NewTask); 
intent.SetAction(Intent.ActionView);
intent.SetType("application/pdf");
intent.PutExtra(Intent.ExtraStream, fileUri);
intent.AddFlags(ActivityFlags.GrantReadUriPermission);
Android.App.Application.Context.StartActivity(intent);

This starts the share dialog for a pdf file but while the Adobe Pdf reader gets opened it shows an empty view and not my pdf file.

Christian
  • 25,249
  • 40
  • 134
  • 225

1 Answers1

4

You need to wrap your URI with FileProvider. Since android uri will give you file:// while FileProvider will give you content://, which you actually need:

public static Android.Net.Uri WrapFileWithUri(Context context,Java.IO.File file)
{
    Android.Net.Uri result;
    if (Build.VERSION.SdkInt < (BuildVersionCodes)24)
    {
        result = Android.Net.Uri.FromFile(file);
    }
    else
    {
        result = FileProvider.GetUriForFile(context, context.ApplicationContext.PackageName + ".provider", file);
    }
    return result;
}

File can be createed this way:

var file = new Java.IO.File(filePath); 

Then you can open it:

    public static void View(Context context, string path, string mimeType) 
    {
        Intent viewIntent = new Intent(Intent.ActionView);
        Java.IO.File document = new Java.IO.File(path);            
        viewIntent.SetDataAndType(UriResolver.WrapFileWithUri(context,document),mimeType);            
        viewIntent.SetFlags(ActivityFlags.NewTask);
        viewIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
        context.StartActivity(Intent.CreateChooser(viewIntent, "your text"));
    }

Be aware, that this line

viewIntent.SetDataAndType(UriResolver.WrapFileWithUri(context,document),mimeType);

does not equal to SetData and SetType separate commands.

And yes, you need to add FileProvider to your manifest:

<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true">
            <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" />
        </provider>

Also you need to create Resources\xml folder with provider_paths.xml file:

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

</paths>
Christian
  • 25,249
  • 40
  • 134
  • 225
Access Denied
  • 8,723
  • 4
  • 42
  • 72
  • Did you put the `WrapFileWithUri`-function into a UriResolver class? – Christian Nov 07 '18 at 11:26
  • @Christian yes, sorry for missing this. – Access Denied Nov 07 '18 at 11:27
  • Is there anything else that the UriResolver class does that is important here? Or can "UriResolver." basically be removed from that code? – Christian Nov 07 '18 at 11:29
  • I'm also not clear where I get a context within Xamarin.Android. – Christian Nov 07 '18 at 11:34
  • 1
    @Christian You can remove UriResolver class definition. Context is an Activity or There is also Application.Context, not quite sure if it will work or not. According to common sence both should work. – Access Denied Nov 07 '18 at 11:43
  • When I create that xml file I get during the startup of my app the error`Java.Lang.RuntimeException: Unable to start activity ComponentInfo{de.ra_micro.RA_Krypt/md5ac266b5641403f314bbc23831457c9e5.SplashActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setId(int)' on a null object reference` whether or not the part about the manifest gets added. – Christian Nov 07 '18 at 12:08
  • delete bin and obj folders on Android project and rebuild it – Access Denied Nov 07 '18 at 13:29
  • I needed to add an additional path for images, but now that works. Thank you very much. – Christian Nov 07 '18 at 14:17
  • This code works well on Google Pixel but when I use it on a Huawei device to share a PDF, roughly every second time the PDF can't be opened. – Christian Feb 28 '19 at 10:17