We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date
Unfortunately, activation email could not send to your email. Please try again.
Syncfusion Feedback

How to share the PDF document in Xamarin.Forms platform?

Platform: Xamarin.iOS |
Control: PdfViewer |
.NET Framework: 4.5.1

PDF documents can be shared by saving the loaded PDF to the file system using the SaveDocument API and share the saved PDF. Refer to the following code snippets.

Portable

Add an interface to the PCL project which defines a method that shares the saved PDF document.

C#

public interface IShare
{
    Task Show(string title, string message, string filePath);
}

 

Add another interface to save the loaded PDF to the file system.

C#

public interface ISave
{
    string Save(MemoryStream fileStream);
}

 

Get the saved file path using the Save method defined in ISave and use this as an argument to share the file using Show method of IShare interface. 

C#

private void OnShareButtonClicked(object sender, EventArgs e)
{
    string filePath = DependencyService.Get<ISave>().Save(pdfViewerControl.SaveDocument() as MemoryStream);
    DependencyService.Get<IShare>().Show("Share", "Sharing PDF", filePath);
}

 

Android

Implement IShare with file sharing options available in Android platform.

C#

//Register the Android implementation of IShare with DependencyService
[assembly: Dependency(typeof(GettingStarted_PDFViewer.Droid.ShareAndroid))]
 
namespace GettingStarted_PDFViewer.Droid
{
    class ShareAndroid : IShare
    {
        private readonly Context context;
        public ShareAndroid()
        {
            context = Android.App.Application.Context;
        }
        public Task Show(string title, string message, string filePath)
        {
            var uri = Android.Net.Uri.Parse("file://" + filePath);
            var contentType = "application/pdf";
            var intent = new Intent(Intent.ActionSend);
            intent.PutExtra(Intent.ExtraStream, uri);
            intent.PutExtra(Intent.ExtraText, string.Empty);
            intent.PutExtra(Intent.ExtraSubject, message ?? string.Empty);
            intent.SetType(contentType);
            var chooserIntent = Intent.CreateChooser(intent, title ?? string.Empty);
            chooserIntent.SetFlags(ActivityFlags.ClearTop);
            chooserIntent.SetFlags(ActivityFlags.NewTask);
            context.StartActivity(chooserIntent);
 
            return Task.FromResult(true);
        }
    }
}

 

Implement ISave with file write options available in Android platform.

C#

//Register the Android implementation of ISave with DependencyService
[assembly:Dependency(typeof(GettingStarted_PDFViewer.Droid.SaveAndroid))]
 
namespace GettingStarted_PDFViewer.Droid
{
    public class SaveAndroid : ISave
    {
        public string Save(MemoryStream stream)
        {
            string root = null;
            string fileName = "SavedDocument.pdf";
            //Get the root folder of the application
            if (Android.OS.Environment.IsExternalStorageEmulated)
            {
                root = Android.OS.Environment.ExternalStorageDirectory.ToString();
            }
            //Create a new folder with name Syncfusion
            Java.IO.File myDir = new Java.IO.File(root + "/Syncfusion");
            myDir.Mkdir();
            //Create a new file with the name fileName in the folder Syncfusion
            Java.IO.File file = new Java.IO.File(myDir, fileName);
            string filePath = file.Path;
            //If the file already exists delete it
            if (file.Exists()) file.Delete();
            Java.IO.FileOutputStream outs = new Java.IO.FileOutputStream(file);
            //Save the input stream to the created file
            outs.Write(stream.ToArray());
            var ab = file.Path;
            outs.Flush();
            outs.Close();
            return filePath;
        }
    }
}

 

iOS

Implement IShare with file sharing options available in iOS platform.

C#

//Register the iOS implementation of IShare with DependencyService
[assembly: Dependency(typeof(GettingStarted_PDFViewer.iOS.ShareiOS))]
 
namespace GettingStarted_PDFViewer.iOS
{
    public class ShareiOS : IShare
    {
        // MUST BE CALLED FROM THE UI THREAD
        public async Task Show(string title, string message, string filePath)
        {
           
 
            var items = new NSObject[] { NSObject.FromObject(title), NSUrl.FromFilename(filePath) };
            var activityController = new UIActivityViewController(items, null);
            var rootController = UIApplication.SharedApplication.KeyWindow.RootViewController;
 
 
            NSString[] excludedActivityTypes = null;
            excludedActivityTypes = new NSString[] { UIActivityType.AssignToContact, UIActivityType.AddToReadingList, UIActivityType.CopyToPasteboard, UIActivityType.SaveToCameraRoll };
 
            if (excludedActivityTypes != null && excludedActivityTypes.Length > 0)
                activityController.ExcludedActivityTypes = excludedActivityTypes;
 
            await rootController.PresentViewControllerAsync(activityController, true);
        }
    }
}

 

Implement ISave with file write options available in iOS platform.

C#

//Register the iOS implementation of ISave with DependencyService
[assembly: Dependency(typeof(GettingStarted_PDFViewer.iOS.SaveiOS))]
 
namespace GettingStarted_PDFViewer.iOS
{
    public class SaveiOS : ISave
    {
        public string Save(MemoryStream fileStream)
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            //The path to which the file is to be saved
            string filepath = Path.Combine(path, "SavedDocument.pdf");
 
            FileStream outputFileStream = File.Open(filepath, FileMode.Create);
            fileStream.Position = 0;
            //Save the input stream of the PDF to the file
            fileStream.CopyTo(outputFileStream);
            outputFileStream.Close();
            return filepath;
        }
    }
}

 

UWP

Implement IShare with file sharing options available in UWP platform.

C#

//Register the UWP implementation of IShare with DependencyService
[assembly: Dependency(typeof(GettingStarted_PDFViewer.UWP.ShareUWP))]
 
namespace GettingStarted_PDFViewer.UWP
{
    class ShareUWP : IShare
    {
        private DataTransferManager dataTransferManager;
        private string filePath;
        private string title;
        private string message;
        public ShareUWP()
        {
            dataTransferManager = DataTransferManager.GetForCurrentView();
            dataTransferManager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(ShareTextHandler);
        }
        public async Task Show(string title, string message, string filePath)
        {
            this.title = title ?? string.Empty;
            this.filePath = filePath;
            message = message ?? string.Empty;
 
            DataTransferManager.ShowShareUI();
        }
        private async void ShareTextHandler(DataTransferManager sender, DataRequestedEventArgs e)
        {
            DataRequest request = e.Request;
 
            // Title is mandatory
            request.Data.Properties.Title = string.IsNullOrEmpty(title) ? Windows.ApplicationModel.Package.Current.DisplayName : title;
 
            DataRequestDeferral deferral = request.GetDeferral();
 
            try
            {
                if (!string.IsNullOrWhiteSpace(filePath))
                {
                    StorageFile attachment = await StorageFile.GetFileFromPathAsync(filePath);
                    List<IStorageItem> storageItems = new List<IStorageItem>();
                    storageItems.Add(attachment);
                    request.Data.SetStorageItems(storageItems);
                }
                request.Data.SetText(message ?? string.Empty);
            }
            finally
            {
                deferral.Complete();
            }
        }
 
    }
}

 

Implement ISave with file write options available in UWP platform.

C#

//Register the UWP implementation of ISave with DependencyService
[assembly: Dependency(typeof(GettingStarted_PDFViewer.UWP.SaveWindows))]
 
namespace GettingStarted_PDFViewer.UWP
{
    public class SaveWindows : ISave
    {
        MemoryStream stream;
        StorageFolder folder;
        StorageFile file;
        public string Save(MemoryStream documentStream)
        {
            documentStream.Position = 0;
            stream = documentStream;
            SaveAsync();
            return Path.Combine(ApplicationData.Current.LocalFolder.Path, "SavedDocument.pdf");
        }
 
        private async void SaveAsync()
        {
            folder = ApplicationData.Current.LocalFolder;
            file = await folder.CreateFileAsync("SavedDocument.pdf", CreationCollisionOption.ReplaceExisting);
            if (file != null)
            {
                Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.ReadWrite);
                Stream st = fileStream.AsStreamForWrite();
                st.SetLength(0);
                st.Write((stream as MemoryStream).ToArray(), 0, (int)stream.Length);
                st.Flush();
                st.Dispose();
                fileStream.Dispose();
            }
        }
    }
}
 

 

Sample link:

http://www.syncfusion.com/downloads/support/directtrac/general/ze/GettingStarted_PDFViewer-1659303577https://www.syncfusion.com/downloads/support/directtrac/general/ze/GettingStarted_PDFViewer-1659303577

 

2X faster development

The ultimate Xamarin UI toolkit to boost your development speed.
ADD COMMENT
You must log in to leave a comment
Comments
Solomon Fried
Jan 31, 2019

A few changes needed for this to work on Android past version 24. 

1. Edit the Android manifest and wit hing the <application></application> xml node, add the following... (replace YOUR_PACKAGE_NAME with your package name.

<provider android:name="android.support.v4.content.FileProvider"
              android:authorities="[YOUR_PACKAGE_NAME].fileprovider"
              android:exported="false"
              android:grantUriPermissions="true">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"></meta-data>
    </provider>

2. Create a folder under Resources called "xml"

3. add a file to the xml directory called file_paths.xml containing the following.. (you probably only need the "files" node)

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

4. In the ShareAndroid class,  
replace var uri = Android.Net.Uri.Parse("file://" + filePath); with ....    var uri = FileProvider.GetUriForFile(context, context.PackageName + ".fileprovider", new File(filePath));

5. Right before context.StartActivity(chooserIntent), add the following

    chooserIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
    chooserIntent.AddFlags(ActivityFlags.GrantWriteUriPermission);

Finally, The Save... classes are not needed and you can use Xamarin.Essentials.FileSystem.AppDataDirectory to get the platform-specific directories.

And that is all folks...

Much thanks to the Xam.Plugins.Messaging team where I found some code in the Email messaging code that helped out here.

You may want to enhance your code to handle older versions of Android (prior to 24) as well. See here for how it was done in the Email plugin

https://github.com/cjlotz/Xamarin.Plugins/blob/master/Messaging/Plugin.Messaging.Android/EmailTask.cs

To the Syncfusion team. Adding a "Share" icon to the PDFViewer with this capability built in would be a really valuable addition.




Reply
Solomon Fried
Jan 31, 2019

I posted the aboce code but my pasted XML seems to have been encoded for me. I will try again.


A few changes needed for this to work on Android past version 24. 

1. Edit the Android manifest and withing the  &lt;application &gt;&lt;/application&gt; xml node, add the following... (replace YOUR_PACKAGE_NAME with your package name.

  &lt;provider android:name="android.support.v4.content.FileProvider"

              android:authorities="com.companyname.ControlsTester.fileprovider"

              android:exported="false"

              android:grantUriPermissions="true"&gt;

      &lt;meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"&gt;&lt;/meta-data&gt;

    &lt;/provider&gt;

2. Create a folder under Resources called "xml"

3. add a file to the xml directory called file_paths.xml containing the following.. (you probably only need the "files" node)

&lt;?xml version="1.0" encoding="utf-8"?&gt;

&lt;paths xmlns:android="http://schemas.android.com/apk/res/android"&gt;

  &lt;external-path name="external" path="." /&gt;

  &lt;external-files-path name="external_files" path="." /&gt;

  &lt;cache-path name="cache" path="." /&gt;

  &lt;external-cache-path name="external_cache" path="." /&gt;

  &lt;files-path name="files" path="." /&gt;

&lt;/paths&gt;

 

4. In the ShareAndroid class,  
replace var uri = Android.Net.Uri.Parse("file://" + filePath); with ....    var uri = FileProvider.GetUriForFile(context, context.PackageName + ".fileprovider", new File(filePath));

5. Right before context.StartActivity(chooserIntent), add the following

    chooserIntent.AddFlags(ActivityFlags.GrantReadUriPermission);
    chooserIntent.AddFlags(ActivityFlags.GrantWriteUriPermission);

Finally, The Save... classes are not needed and you can use Xamarin.Essentials.FileSystem.AppDataDirectory to get the platform-specific directories.

And that is all folks...

Much thanks to the Xam.Plugins.Messaging team where I found some code in the Email messaging code that helped out here.

https://github.com/cjlotz/Xamarin.Plugins/blob/master/Messaging/Plugin.Messaging.Android/EmailTask.cs

You may want to enhance your code to handle older versions of Android (prior to 24) as well. See here for how it was done in the Email plugin



To the Syncfusion team. Adding a "Share" icon to the PDFViewer with this capability built in would be a really valuable addition.

Karthik Krishnaraj [Syncfusion]
Feb 01, 2019

Hi Solomon,

 

Thank you for your suggestion,

 

We will check through it and modify the sample accordingly.

 

Regards,

Karthik.

Please sign in to access our KB

This page will automatically be redirected to the sign-in page in 10 seconds.

Up arrow icon

Warning Icon You are using an outdated version of Internet Explorer that may not display all features of this and other websites. Upgrade to Internet Explorer 8 or newer for a better experience.Close Icon

Live Chat Icon For mobile