Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open Pdf File in Xamarin.forms

Currently I'm writing a Privacy policy for apps that I put in PDF format.
May I ask about how to open PDF file for Xamarin.Forms? Any references Source Code?

like image 256
Eng Soon Cheah Avatar asked Dec 16 '16 02:12

Eng Soon Cheah


1 Answers

It all depends a bit on the fact if your PDF file is hosted elsewhere or locally on the device.

Hosted

If it is hosted online; the easiest way would be to just do a Device.OpenUri() with the URI of the PDF file, but this would open an external browser.

If you want to incorporate it within your app you can create a page with a WebView and navigate to the PDF in there. This should be pretty straight-forward.

Implement a page with a WebView, I'm going to assume you use XAML.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="DisplayPDF.WebViewPage"
             Padding="0,20,0,0">
    <ContentPage.Content>
        <WebView Source="http://www.yoursite.com/your.pdf" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
    </ContentPage.Content>
</ContentPage>

Local

Local on the device there is no unified way to do this. One way is to implement it through showing it in a WebView, which is basically the same as the WebView above, but you need to create a CustomRenderer for each platform you want to use. You can use the link provided by dylansturg as a reference.

Basically you implement the same page with a custom WebView component.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DisplayPDF;assembly=DisplayPDF"
             x:Class="DisplayPDF.WebViewPage"
             Padding="0,20,0,0">
    <ContentPage.Content>
        <local:CustomWebView Uri="your.pdf" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
    </ContentPage.Content>
</ContentPage>

Your custom WebView will look like this:

public class CustomWebView : WebView
{
    public static readonly BindableProperty UriProperty = BindableProperty.Create (propertyName:"Uri",
            returnType:typeof(string),
            declaringType:typeof(CustomWebView),
            defaultValue:default(string));

    public string Uri {
        get { return (string)GetValue (UriProperty); }
        set { SetValue (UriProperty, value); }
    }
}

It's basically just a WebView but we add a Uri property to it.

iOS

Now if you want to implement it for iOS, create a CustomRenderer in your platform project and implement it somewhat like this:

[assembly: ExportRenderer (typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace DisplayPDF.iOS
{
    public class CustomWebViewRenderer : ViewRenderer<CustomWebView, UIWebView>
    {
        protected override void OnElementChanged (ElementChangedEventArgs<CustomWebView> e)
        {
            base.OnElementChanged (e);

            if (Control == null) {
                SetNativeControl (new UIWebView ());
            }
            if (e.OldElement != null) {
                // Cleanup
            }
            if (e.NewElement != null) {
                var customWebView = Element as CustomWebView;
                string fileName = Path.Combine (NSBundle.MainBundle.BundlePath, string.Format ("Content/{0}", WebUtility.UrlEncode (customWebView.Uri)));
                Control.LoadRequest (new NSUrlRequest (new NSUrl (fileName, false)));
                Control.ScalesPageToFit = true;
            }
        }
    }
}

Here you see how we create a native UIWebView and navigate it a file which is provided with our app. Note: the file should be in the Content file and marked as a BundleResource. If you are to download the file (or new versions of the policy) make sure you adjust the path accordingly.

Android

For Android it's a bit more work, you have to download the pdf.js library add it to you project under Assets. Make sure to check if the files are added to your repository as well. In my case the .js files where in my .gitignore file by default.

Now create a custom renderer like this:

[assembly: ExportRenderer (typeof(CustomWebView), typeof(CustomWebViewRenderer))]
namespace DisplayPDF.Droid
{
    public class CustomWebViewRenderer : WebViewRenderer
    {
        protected override void OnElementChanged (ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged (e);

            if (e.NewElement != null) {
                var customWebView = Element as CustomWebView;
                Control.Settings.AllowUniversalAccessFromFileURLs = true;
                Control.LoadUrl (string.Format ("file:///android_asset/pdfjs/web/viewer.html?file={0}", string.Format ("file:///android_asset/Content/{0}", WebUtility.UrlEncode (customWebView.Uri))));
            }
        }
    }
}

Notice how we navigate to the pdf.js library here and provide it with a query parameter to specify our PDF file. Again, this is when you provide the file with the app. Also this is only available from API 19 and up.

For Windows you should also use the pdf.js library.

As per Nikolai's kind response it seems there is also a lightweight pdf.js lib for mobile I didn't us it myself yet, but it seems better to use for mobile use.

Since this question still seems relevant I thought it would be nice to update it with a more thorough blog post I did on this.

like image 89
Gerald Versluis Avatar answered Oct 25 '22 01:10

Gerald Versluis