Unable to Open PDF into the third-party app

santyrautsantyraut Member ✭✭
edited March 2018 in Xamarin.Forms

Hi,

I am downloading file into download folder. A pdf file is downloaded properly but unable to open into third-party app.

  1. If I select Target SDK : Automatic into the droid then it works perfectly. I am able to show pdf file with the third-party app. But with this selection, I can't publish app on the play store. It throws an error Target SDK should be 23 or greater.

  2. If I select Target SDK other than automatic then it's not allowing to open PDF file into the third-party app.
    Please see my code below.

public void OpenFile(string filePath)
{
string externalStorageState = global::Android.OS.Environment.ExternalStorageState;
string application = "";

        string extension = System.IO.Path.GetExtension(filePath);

        switch (extension.ToLower())
        {
            case ".doc":
            case ".docx":
                application = "application/msword";
                break;
            case ".pdf":
                application = "application/pdf";
                break;
            case ".xls":
            case ".xlsx":
                application = "application/vnd.ms-excel";
                break;
            case ".jpg":
                application = "image/jpeg";
                break;
            case ".jpeg":
                application = "image/jpeg";
                break;
            case ".png":
                application = "image/png";
                break;
            default:
                application = "*/*";
                break;
        }
        //var externalPath = global::Android.OS.Environment.ExternalStorageDirectory.Path + "/report" + extension;
        //File.WriteAllBytes(externalPath, bytes);

        //Java.IO.File file = new Java.IO.File(externalPath);
        Java.IO.File file = new Java.IO.File(filePath);
        file.SetReadable(true);
        //Android.Net.Uri uri = Android.Net.Uri.Parse("file://" + filePath);
        Android.Net.Uri uri = Android.Net.Uri.FromFile(file);
        Intent intent = new Intent(Intent.ActionView);
        intent.SetDataAndType(uri, application);
        intent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);

        try
        {
            Xamarin.Forms.Forms.Context.StartActivity(intent);
        }
        catch (Exception)
        {
            Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application Available to View this file.", ToastLength.Short).Show();
        }
    }

The code is crashing on this line Xamarin.Forms.Forms.Context.StartActivity(intent);

Please help me.

Best Answer

  • santyrautsantyraut ✭✭
    edited January 29 Accepted Answer

    Hi

    Finally, I found the solution for this.

    Actual Problem is file:// URI is not working for android version nougat onwards. If you want to open downloaded file(PDF, Video, image etc...) then you have to use content:// URI (FileProvider) instead of file:// URI. Please check the code below for better understanding.

    Before using FileProvider we need to add some code into the manifest file.
    com.xam.santy is package name of my project. You can add yours.

    We’re going to set android:exported to false because we don’t need it to be public,
    android:grantUriPermissions to true because it will grant temporary access to files and
    android:authorities to a domain you control,
    so if your domain is com.xam.santy then you can use something like com.xam.santy.fileprovider.
    The authority of a provider should be unique and that’s the reason why we are using our application ID plus something like fileprovider


    Then we need to create the file_provider_path in the drawable folder. That’s the file which defines the folders which contain the files you will be allowed to share safely. In our case we just need access to the external storage folder:
    <?xml version="1.0" encoding="UTF-8" ?>


    Finally, we just have to change our code:

    OpenFile method has 2 parameters filename (abc.pdf) and filePath (/storage/emulated/0/Download/abc.pdf)

    public void OpenFile(string filename, string filePath)
    {
    string application = "";

            string extension = System.IO.Path.GetExtension(filePath);
    
            switch (extension.ToLower())
            {
                case ".doc":
                case ".docx":
                    application = "application/msword";
                    break;
                case ".pdf":
                    application = "application/pdf";
                    break;
                case ".xls":
                case ".xlsx":
                    application = "application/vnd.ms-excel";
                    break;
                case ".jpg":
                    application = "image/jpeg";
                    break;
                case ".jpeg":
                    application = "image/jpeg";
                    break;
                case ".png":
                    application = "image/png";
                    break;
                default:
                    application = "*/*";
                    break;
            }
    
            Java.IO.File file = new Java.IO.File(filePath);
    
            file.SetReadable(true);
            Android.Net.Uri uri = Android.Support.V4.Content.FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context, "com.xam.santy.fileprovider", file);
    
            Intent intent = new Intent(Intent.ActionView);
            intent.SetDataAndType(uri, application);
            intent.AddFlags(ActivityFlags.GrantReadUriPermission);
            intent.AddFlags(ActivityFlags.NoHistory);
            intent.AddFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
    
            try
            {
                Xamarin.Forms.Forms.Context.StartActivity(intent);
            }
            catch (Exception)
            {
                Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application Available to View this file.", ToastLength.Short).Show();
            }
        }
    
        Above method has 2 changes.
        1. Content URI
        2. Intent Flag
    
        1. Conter URI
         Android.Net.Uri uri = Android.Support.V4.Content.FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context, "com.xam.santy.fileprovider", file);
    
         GetUriForFile takes 3 parameters
         Android.Support.V4.Content.FileProvider.GetUriForFile(Context, authority, file);
    
         2. Intent Flag
         To open file we need grant permissions. This can be achieved by adding flag.
          intent.AddFlags(ActivityFlags.GrantReadUriPermission);
          intent.AddFlags(ActivityFlags.NoHistory);
    
          After this, you can open a file into the third-party app successfully.
    

Answers

  • santyrautsantyraut Member ✭✭

    Hi Alessandro,

    Thanks for the reply. But Above solution will not help. My App has multiple type of files like PDF, Video and Image. Above Solution is PDF file specific. And I don't want to open it on inApp. It should show available/installed third-party app for desired file view. So user can select on of them and view the downloaded file.

  • santyrautsantyraut Member ✭✭
    edited January 29 Accepted Answer

    Hi

    Finally, I found the solution for this.

    Actual Problem is file:// URI is not working for android version nougat onwards. If you want to open downloaded file(PDF, Video, image etc...) then you have to use content:// URI (FileProvider) instead of file:// URI. Please check the code below for better understanding.

    Before using FileProvider we need to add some code into the manifest file.
    com.xam.santy is package name of my project. You can add yours.

    We’re going to set android:exported to false because we don’t need it to be public,
    android:grantUriPermissions to true because it will grant temporary access to files and
    android:authorities to a domain you control,
    so if your domain is com.xam.santy then you can use something like com.xam.santy.fileprovider.
    The authority of a provider should be unique and that’s the reason why we are using our application ID plus something like fileprovider


    Then we need to create the file_provider_path in the drawable folder. That’s the file which defines the folders which contain the files you will be allowed to share safely. In our case we just need access to the external storage folder:
    <?xml version="1.0" encoding="UTF-8" ?>


    Finally, we just have to change our code:

    OpenFile method has 2 parameters filename (abc.pdf) and filePath (/storage/emulated/0/Download/abc.pdf)

    public void OpenFile(string filename, string filePath)
    {
    string application = "";

            string extension = System.IO.Path.GetExtension(filePath);
    
            switch (extension.ToLower())
            {
                case ".doc":
                case ".docx":
                    application = "application/msword";
                    break;
                case ".pdf":
                    application = "application/pdf";
                    break;
                case ".xls":
                case ".xlsx":
                    application = "application/vnd.ms-excel";
                    break;
                case ".jpg":
                    application = "image/jpeg";
                    break;
                case ".jpeg":
                    application = "image/jpeg";
                    break;
                case ".png":
                    application = "image/png";
                    break;
                default:
                    application = "*/*";
                    break;
            }
    
            Java.IO.File file = new Java.IO.File(filePath);
    
            file.SetReadable(true);
            Android.Net.Uri uri = Android.Support.V4.Content.FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context, "com.xam.santy.fileprovider", file);
    
            Intent intent = new Intent(Intent.ActionView);
            intent.SetDataAndType(uri, application);
            intent.AddFlags(ActivityFlags.GrantReadUriPermission);
            intent.AddFlags(ActivityFlags.NoHistory);
            intent.AddFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask);
    
            try
            {
                Xamarin.Forms.Forms.Context.StartActivity(intent);
            }
            catch (Exception)
            {
                Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application Available to View this file.", ToastLength.Short).Show();
            }
        }
    
        Above method has 2 changes.
        1. Content URI
        2. Intent Flag
    
        1. Conter URI
         Android.Net.Uri uri = Android.Support.V4.Content.FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context, "com.xam.santy.fileprovider", file);
    
         GetUriForFile takes 3 parameters
         Android.Support.V4.Content.FileProvider.GetUriForFile(Context, authority, file);
    
         2. Intent Flag
         To open file we need grant permissions. This can be achieved by adding flag.
          intent.AddFlags(ActivityFlags.GrantReadUriPermission);
          intent.AddFlags(ActivityFlags.NoHistory);
    
          After this, you can open a file into the third-party app successfully.
    
  • mra1mra1 Member ✭✭

    I still get this error... what is wrong there?

    Java.Lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.ProviderInfo.loadXmlMetaData(android.content.pm.PackageManager, java.lang.String)' on a null object reference

    Android.Net.Uri uri = Android.Support.V4.Content.FileProvider.GetUriForFile(Xamarin.Forms.Forms.Context, "Iaswebde.BDE.Droid.fileprovider", file);
    
    <provider android:name="android.support.v4.content.FileProvider" android:authorities="Iaswebde.BDE.Droid.fileprovider" android:exported="false" android:grantUriPermissions="true">
        <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
    </provider>
    
  • ruborubo USMember ✭✭

    @mra1 I believe this is the answer for you.

  • mra1mra1 Member ✭✭

    @rubo said:
    @mra1 I believe this is the answer for you.

    oh perfect, thanks! ;)

Sign In or Register to comment.