Open PDF in Android default PDF reader

SimonDelliseSimonDellise BEMember ✭✭

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 BEMember ✭✭
    edited May 2015

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

  • Mariano.7927Mariano.7927 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 USMember
    edited September 2015

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

  • SimonDelliseSimonDellise BEMember ✭✭

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

  • AlessandroCaliaroAlessandroCaliaro 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 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 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 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 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 USMember

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

  • JacobPoulsen_JacobPoulsen_ 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!

  • 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_ DKMember ✭✭✭

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

  • Diorrini11Diorrini11 USMember

    @AlessandroCaliaro

    Instead of the huge Switch you can just use this:

    string application = MimeTypeMap.Singleton.GetMimeTypeFromExtension(MimeTypeMap.GetFileExtensionFromUrl(uri.Path));
    
  • ThomasMielkeThomasMielke 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 USMember ✭✭✭

    Thanks for this piece of code @AlessandroCaliaro

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭
    ;) happy Christmas
  • Garyb99Garyb99 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 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 USMember ✭✭

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

  • MohanadZahedMohanadZahed DEMember ✭✭
    edited September 6

    Hi, can anyone explain why the external storage thing? I mean why don't we just add the extension to the filePath directly and then open the file?

  • VulcanVulcan TWMember ✭✭✭

    @AlessandroCaliaro

    How can I design open file function in iOS?

Sign In or Register to comment.