Open PDF in Android default PDF reader

SimonDelliseSimonDellise Simon DelliseBEMember

Hi,

I'm searching a way to open a PDF (stored in local) in the Android default PDF reader in Xamarin.Forms.
I'm using a webview for iOS but WebViews on Android cannot open a local PDF.

var browser = new WebView ();

if (Device.OS == TargetPlatform.iOS) {
    browser.Source = @App.DocumentUrl;
} else if (Device.OS == TargetPlatform.Android) {
    Device.OpenUri (new Uri (@App.DocumentUrl)); // Don't work
}

Content = browser;

Did someone have a solution ?

Thanks.

Tagged:

Posts

  • SimonDelliseSimonDellise Simon Dellise BEMember
    edited May 2015

    Thanks a lot @AlessandroCaliaro , it works for me :)

  • Mariano.7927Mariano.7927 Mariano USMember
    edited September 2015

    Thanks a lot @AlessandroCaliaro, it worked for me too! i posted your answer in another post giving you the right credits, this should be solution number 1.

  • ADeCraemerADeCraemer Arne De Craemer USMember
    edited September 2015

    @AlessandroCaliaro, @Mariano.7927
    Does your solution also work for pdf's that are stored inside the asset folder?

  • SimonDelliseSimonDellise Simon Dellise BEMember

    @ADeCraemer my pdf are stored in local (in Environment.SpecialFolder.ApplicationData) and it works ... if it can help you

  • AlessandroCaliaroAlessandroCaliaro Alessandro Caliaro ITMember ✭✭✭✭✭

    @ADeCraemer yes, but you have to "copy" your file present in "Asset" to anothed local directory. You can do it in your Android or iOS project.

  • ADeCraemerADeCraemer Arne De Craemer USMember

    @AlessandroCaliaro So i can just put the PDF in a random folder in my project? And does my pdf needs to have a specific build action? Atm it has the build action AndroidAsset. Do I need to change it?

  • AlessandroCaliaroAlessandroCaliaro Alessandro Caliaro ITMember ✭✭✭✭✭

    You have to put your file in a folder accesible from your app.

    This can help you

    http://stackoverflow.com/questions/7018445/monodroid-copying-an-asset-to-sd-card

  • VolodymyrSavchenkoVolodymyrSavchenko Volodymyr Savchenko UAMember ✭✭

    AlessandroCaliaro,
    could you please explain, what is the best way to access this code from Shared Project? Is Device.OnPlatform right choice?
    Also same code to open PDF in default pdf reader needed for iOS0 and, if you have some, for WP.

    Thanks for sharing your code.

  • AlessandroCaliaroAlessandroCaliaro Alessandro Caliaro ITMember ✭✭✭✭✭

    This is a post to open PDF in android. At the top of this page you can find a code to open various types of files in android using natives apps. You have to call this code in your PCL prj using the dependencyservice.

    The stack layout links is to move pdf from assets to a directory. You can use it on android prj at startup.

  • ADeCraemerADeCraemer Arne De Craemer USMember

    @AlessandroCaliaro Thnx for helping me! It is working now.

  • JacobPoulsen_JacobPoulsen_ Jacob Poulsen DKMember ✭✭✭
    edited October 2015

    Hi! Great example @AlessandroCaliaro, works like a charm.
    My only concern about this method is, that anyone can download a File Explorer App, and navigate to the external folder path and manipulate the file from there.
    Has anyone made a solution to this, so that the file gets deleted consistently? I've tried with Java.IO.File.DeleteOnExit(), but this will not always delete the file. Anyone has a better solution? Right now im at something like this:

    try
    {
        Xamarin.Forms.Forms.Context.StartActivity(intent);
    }
    catch (Exception)
    {
        Toast.MakeText(Xamarin.Forms.Forms.Context, "No Application Available to View PDF", ToastLength.Short).Show();
    }
    finally
    {
        await Task.Delay (3000);
        File.Delete (externalPath);
    }
    

    But it is so UGLY and will throw an error if the user tries to forward the PDF using the Intent, because the file would no longer be present.

    The file cannot be opened using PDF readers if its placed in Environment.SpecialFolder.Personal , or at least i cannot make it work.

    Im open to any suggestions.

    Cheers!

  • ThiagoGrandessoThiagoGrandesso Thiago Grandesso USMember

    Hi @JacobPoulsen_ ,

    Have you found any solution to your question?

    I´m using the same code (works great!) but am at the same issue you mentioned.

  • JacobPoulsen_JacobPoulsen_ Jacob Poulsen DKMember ✭✭✭

    @ThiagoGrandesso I didn't :(
    Let me know if you find a clever way to handle this :)

  • Diorrini11Diorrini11 Diogo Coelho USMember

    @AlessandroCaliaro

    Instead of the huge Switch you can just use this:

    string application = MimeTypeMap.Singleton.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl(uri.Path));
    
  • ThomasMielkeThomasMielke Thomas Mielke DEMember ✭✭

    @Diorrini11 said:
    @AlessandroCaliaro

    Instead of the huge Switch you can just use this:

    string application = MimeTypeMap.Singleton.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl(uri.Path));

    Note: GetMimeTypeFromExtension() is case sensitive. I'd recommend this form, in case of a DOSsy file name like IMAGE.JPG:

    MimeTypeMap.Singleton.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl(uri.Path.ToLower()));

  • 15mgm1515mgm15 Mario Galvan USMember ✭✭✭

    Thanks for this piece of code @AlessandroCaliaro

  • AlessandroCaliaroAlessandroCaliaro Alessandro Caliaro ITMember ✭✭✭✭✭
    ;) happy Christmas
  • Garyb99Garyb99 Gerrit Bergen USMember ✭✭

    @AlessandroCaliaro I know this is an old thread, and I hate to dig it back up, but what would be the equivalent of this dependency in IOS? Thanks alot for your help!

  • AlessandroCaliaroAlessandroCaliaro Alessandro Caliaro ITMember ✭✭✭✭✭

    yes, old code... I don't know if it works again

    public class MyOpenFile : IOpenFile
    {
        public MyOpenFile ()
        {
        }
    

    // public void OpenFile(string filePath)
    // {
    // string filename = System.IO.Path.GetFileName (filePath);
    // string currentFilePath = System.IO.Path.GetDirectoryName (filePath);
    //
    // QLPreviewItemBundle prevItem = new QLPreviewItemBundle (filename, currentFilePath);
    // QLPreviewController previewController = new QLPreviewController ();
    // previewController.DataSource = new PreviewControllerDS (prevItem);
    // NavigationController.PushViewController (previewController, true);
    // }

        public string GetTempPath(){
            return Path.GetTempPath ();
        }
    
        public void OpenFile (string targetPath)
        {
    

    //// string filename = System.IO.Path.GetFileName (filePath);
    //// string currentFilePath = System.IO.Path.GetDirectoryName (filePath);
    //// string path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
    //// string filePath = Path.Combine(path, "sample.pdf");
    // var viewer = UIDocumentInteractionController.FromUrl(NSUrl.FromFilename(filePath));
    // viewer.PresentOptionsMenu(new RectangleF(0,-260,320,320),true, true);
    // //viewer.PresentPreview(false);

            string name = Path.GetFileName(targetPath);
            Device.BeginInvokeOnMainThread(() =>
                {
                    QLPreviewItemFileSystem prevItem = new QLPreviewItemFileSystem(name, targetPath);
                    QLPreviewController previewController = new QLPreviewController();
                    previewController.DataSource = new PreviewControllerDS(prevItem);
                    UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(previewController, true, null);
                });
        }
    }
    
    public class PreviewControllerDS : QLPreviewControllerDataSource
    {
        private QLPreviewItem _item;
    
        public PreviewControllerDS(QLPreviewItem item)
        {
            _item = item;
        }
    
        public override IQLPreviewItem GetPreviewItem(QLPreviewController controller, nint index)
        {
            return _item;
        }
    
        public override nint PreviewItemCount(QLPreviewController controller)
        {
            return 1;
        }
    }
    
    public class QLPreviewItemFileSystem : QLPreviewItem
    {
        string _fileName, _filePath;
    
        public QLPreviewItemFileSystem(string fileName, string filePath)
        {
            _fileName = fileName;
            _filePath = filePath;
        }
    
        public override string ItemTitle
        {
            get
            {
                return _fileName;
            }
        }
        public override NSUrl ItemUrl
        {
            get
            {
                return NSUrl.FromFilename(_filePath);
            }
        }
    }
    
  • Garyb99Garyb99 Gerrit Bergen USMember ✭✭

    @AlessandroCaliaro Thank you! This worked perfectly! :smile:

Sign In or Register to comment.