Share в Xamarin.Forms – совместное использование файлов и документов

Автор:

c-sharpcorner.com

Совместное использование контента в мобильных приложениях является одной из наиболее важных функций с точки зрения удобства использования приложения и выходит за рамки концепции совместного использования в социальных сетях. Например, если вы получаете документ PDF по электронной почте и хотите открыть его в приложении для просмотра PDF, таком как Adobe Reader, вы фактически делитесь документом из почтового клиента с приложением для просмотра PDF. Аналогично вы можете обмениваться файлами на ваших устройствах, такими как фотографии и видео, в чате WhatsApp.

Вы просите операционную систему открыть другое приложение, которое достаточно открыто для получения содержимого из других приложений. В мобильном приложении, работающем с данными, распространенным сценарием является получение документа через веб-API, отображение документа в приложении и возможность отправить его по электронной почте некоторым получателям. Таким образом, на более высоком уровне под совместным использованием мы обычно подразумеваем обмен содержимым с другим приложением.

Использование Xamarin.Forms для создания платформо-независимых приложений

Совместное использование содержимого в Xamarin.Forms упрощается благодаря классу Share, предлагаемому библиотекой Xamarin.Essentials. Этот класс предоставляет статический метод RequestAsync, который получает аргумент, который может быть следующих типов:

  • String – для обмена обычным текстом;
  • ShareTextRequestдля передачи URI или текста;
  • ShareFileRequest – для передачи файлов.

В этой статье рассмотрим подробно тип ShareFileRequest.

Класс ShareFileRequest указывает на локальный путь к файлу. В нашем примере PDF-документ хранится как встроенный ресурс текущего проекта, поэтому требуется дополнительный шаг, чтобы получить файл из ресурсов, скопировать его в каталог приложения, а затем указать на полученное имя. Для этого используется следующий метод, называемый ShareAsync:

 private async Task ShareAsync()
{
    string resourcesPath = "ILive.Core.Resources";
    string fileName = "SampleDoc.pdf";
 
    var fileStream = this.GetType()
	.Assembly
	.GetManifestResourceStream($"{resourcesPath}.{fileName}");
 
    var cacheFile = Path.Combine(FileSystem.CacheDirectory, fileName);
    using (var file = new FileStream(cacheFile, FileMode.Create, FileAccess.Write))
    {
        fileStream.CopyTo(file);
    }
    var request = new ShareFileRequest();
 
    request.Title = "Share document";
    request.File = new ShareFile(cacheFile);
    await Share.RequestAsync(request);
}

Первая строка получает файл, хранящийся во встроенных ресурсах в виде потока Stream. Переменная cacheFile объединяет путь к каталогу кэша приложения и имя файла в одно имя. Блок using создает экземпляр класса FileStream, указывающий на поток исходного файла, создавая его копию в целевом каталоге. Блок using обеспечивает утилизацию ресурсов потока после использования. Объект ShareFileRequest может указывать на локальный путь через свойство File. Свойство Title позволяет указать заголовок для пользовательского интерфейса совместного доступа, если он поддерживается ОС. Метод ShareAsync вызывается обработчиком события Clicked для кнопки ShareButton следующим образом:

 private async void ShareButton_Clicked(object sender, EventArgs e)
{
   await ShareAsync();
}

Если теперь запустить приложение и нажать кнопку Поделиться после открытия документа, вы получите результат, выглядящий примерно так:

Результат почти наверняка будет отличаться на вашем устройстве, поскольку он зависит от того, сколько и какие приложения для поддержки документов PDF у вас установлены (в нашем случае для Android используют эмулятор, на котором не установлены приложения для работы с PDF, и поэтому он показывает только параметры устройства). Вам просто нужно будет выбрать приложение, поддерживающее прием PDF-документов, и файл будет передан с помощью системного интерфейса, без необходимости писать код для конкретной платформы, что является невероятным преимуществом. Приложение, которое получит документ, будет знать, как с ним поступить. Например, если вы выберете почтовый клиент для совместного использования, документ будет автоматически добавлен в качестве вложения в новое сообщение электронной почты.

Ниже представлены пример нативной (платформо-зависимой) реализации шаринга:

Xamarin.iOS

Приложения Xamarin.iOS работают в среде исполнения Mono и используют компиляцию AOT (full Ahead of Time) для компиляции кода C# в native. Среда выполнения Mono написана на языке C и работает совместно с Objective-C Runtime. Обе среды выполнения работают поверх UNIX-подобного ядра, а именно XNU, и предоставляют различные API для доступа к базовой системе iOS.

public void Share(List imageFilesPath)
{
    var activityItems = new NSObject[imageFilesPath.Count];
 
    for (int i = 0; i < imageFilesPath.Count; i++)
    {
        activityItems[i] = new NSUrl(imageFilesPath[i], false);
    }
 
	UIActivityViewController activityViewController = 
    new UIActivityViewController(activityItems, null)
         {
             ExcludedActivityTypes = new NSString[] { UIActivityType.SaveToCameraRoll }
         };
 
     UIViewController viewController = UIApplication
	.SharedApplication
	.KeyWindow
	.GetTopModalHostViewController();
 
     viewController?.PresentViewController(activityViewController, true, null);
}

Xamarin.Android

Как и в Xamarin.iOS, приложения Xamarin.Android запускаются в среде исполнения Mono. Среда выполнения Mono написана на языке C и работает бок о бок с виртуальной машиной Android Runtime (ART). Обе среды выполнения работают поверх ядра Linux и предоставляют различные API для доступа к базовой системе android.

В приложениях Xamarin.Android вы можете получить доступ к различным низкоуровневым функциям операционной системы Android либо путем вызова API .NET, либо используя классы, открытые в пространствах имен Android, которые обеспечивают мост к API Java, открываемым Android Runtime.

public void Share(List imageFilesPath)
{
    string authority = "com.ILive.Droid.fileprovider";
 
    var imagesUri = new List();
    foreach (var imageFilePath in imageFilesPath)
    {
        try
        {
            var file = new File(imageFilePath);
            var uriForFile = FileProvider.GetUriForFile(
	Application.Context, 
	authority,
	file);
 
            imagesUri.Add(uriForFile);
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(
	$"Can't get uri for path {imageFilePath}. Exception: {ex.Message}");
        }
    }
 
    try
    {
        var shareIntent = new Intent(Intent.ActionSendMultiple);
        shareIntent.PutParcelableArrayListExtra(Intent.ExtraStream, imagesUri);
        shareIntent.SetType("image/*");
        shareIntent.AddFlags(ActivityFlags.NewTask);
        Application.Context.StartActivity(shareIntent);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(
	$"Can't start share intent. Exception: {ex.Message}");    
    }
}

Материалы по теме