Пересылка файлов между приложениями является довольно специфической функцией для ОС. И это то, что лучше не пытаться сделать в Xamarin.Forms, не так ли? На самом деле сделать это довольно просто, и этот пост продемонстрирует как заполучить эту функцию и запустить в iOS (в следующем посте будет рассмотрен случай с Android и, при необходимости, с UWP).
Это распространенная практика использования мобильных приложений: открытие файла в одном приложении и необходимость использования другого для дальнейшей обработки этого файла. Например, вы открыли PDF файл, и появилась необходимость внести некоторые изменения в этом файле в другом приложении. При тапе на этом PDF файле на экране появится меню «Открыть в», позволяя импортировать данный файл в предпочитаемое приложение.
Стоит отметить, что в этом посте речь пойдет не о создании расширения приложения к iOS фрагменту Forms решения, чтобы появлялось приложение, когда пользователь тапает кнопку «Поделиться» (маленький прямоугольник с выходящей из него стрелкой). В данном случае будет рассмотрена передача файла в Forms приложение, а не обмен контентом между приложениями.
Сценарий
Приведенный в этом посте пример — это Xamarin.Forms приложение, зарегистрированное для возможности открытия PDF файлов и последующего отображения их в WebView. Здесь будут рассмотрены основы регистрации для iOS, а значит и для Xamarin.Forms (Это также применимо и для Android).
iOS регистрация
Когда я говорю, что Forms приложение будет зарегистрировано, то имеется в виду, что оно будет работать как этих скриншотах. В Safari открыта страница с PDF файлом.
Приложение называется «OpenForms», и на первом скриншоте iOS предоставляет возможность напрямую открыть файл с помощью быстрой команды «Open In OpenForms».
На втором скриншоте при тапе на меню «More» внизу появится окно со списком действий. Здесь виден ярлык нужного приложения.
Info.plist
Чтобы iOS поняла, что данное приложение может обрабатывать PDF файлы, необходимо скорректировать файл Info.plist. Нужно добавить новый ключ верхнего уровня. Можно сделать это с помощью встроенного в Xamarin Studio редактора или отредактировать напрямую.
Чтобы использовать Xamarin Studio, нужно дважды кликнуть на Info.Plist, и тогда откроется встроенный редактор. Выберите вкладку «Advanced» внизу экрана. В разделе «Document Types» в самом вверху кликните кнопку «Add Document Type». Это добавит раздел как на скриншоте ниже.
Вот так нужно его заполнить.
Name: Любое имя. Оно понадобится для ссылки позднее.
Types: Это превратиться в массив определенных строк. Подробнее об этом ниже.
Icons: Расположение ярлыков, которые будут отображаться в меню «More», вместо главного ярлыка приложения. Опять же это может превратиться в массив строк, если будет больше одного ярлыка.
Заполнение таким образом изменит Info.plist и позволит зарегистрировать приложение для открытия файлов других типов. Но здесь стоит разобраться подробнее, чтобы понять, что меняется в Info.plist. Оказывается, что в этот файл можно добавить дополнительные ключи, что не всегда получается сделать в IDE.
Вот весь словарь, который был использован для регистрации открытия файлов нужного типа.
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>PDF</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSHandlerRank</key>
<string>Alternate</string>
<key>LSItemContentTypes</key>
<array>
<string>com.adobe.pdf</string>
</array>
</dict>
</array>
CFBundleDocumentTypes
— ключ словаря верхнего уровня, который в свою очередь содержит массив других объектов словаря:
CFBundleTypeName
. Этот ключ содержит имя типа документа для ссылки на тип.CFBundleTypeRole
. Этот ключ позволяет ОС определить приложение, которое будет обрабатывать файл данного типа. В конкретном случае — это Viewer.LSHandlerRank
. Определяет уровень значимости приложения для типов файлов. Microsoft Word назначен по умолчанию для Word файлов. Для нашего приложения установлено значение Alternate.LSItemContentTypes
. Массив строк. Здесь определяются файлы типы файлов, которые приложение сможет открывать.
Все довольно просто, за исключением LSItemContentTypes
. Где взять эти значения? Для этой цели есть Uniform Type Identifier. Это строка, которая идентифицирует тип файла. Список публично зарегистрированных строк можно найти на этой странице документации Apple.
Теперь нужно понять, как iOS дает знать приложению, что есть файл, ожидающий открытия.
Ответ на открытые iOS события
Когда кто-нибудь выбирает данное приложение, чтобы открыть PDF файл, вызывается следующая функция:
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
iOS копирует файл, который нужно открыть этим приложением, в хранилище, к которому у приложения есть доступ и которое указано с помощью параметра NSUrl url
. Далее необходимо обработать этот файл в Xamarin.Forms.
Тогда AppDelegate будет выглядеть так:
App mainForms;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
mainForms = new App();
LoadApplication(mainForms);
return base.FinishedLaunching(app, options);
}
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
mainForms.DisplayThePDF(url.Path);
return true;
}
Здесь есть пара необычных моментов. Во-первых, сохранена локальная переменная Xamarin.Forms mainForms
класса App
в AppDelegate. Она понадобится позднее как точка входа для отображения PDF.
Также в функции OpenUrl
была вызвана функция DisplayPDF()
переменной mainForms
. Это обеспечит отображение PDF в Xamarin.Forms. В идеале нужно было бы скопировать PDF и удалить исходник, указанный параметром url, чтобы очистить место. Но не в этом случае.
Xamarin.Forms!
Я потратил много времени, рассказывая о настройке со стороны iOS. Однако, когда начинается работа в реальном проекте, то часть iOS — это не более чем формальность. Настоящая работа начинается со стороны Xamarin.Forms: как обработать входящий файл. Для этого я оставил комментарий по отображению PDF к статье, которую нашел на сайте Xamarin. Здесь рассказано о настройке рендерера.
Далее хотелось бы сосредоточиться на точке входа в Forms решение.
В файле App.xaml.cs
или классе App
(класс к которому AppDelegate имеет доступ) есть функция, определяющая взаимодействие между iOS и Forms проектами:
public void DisplayThePDF(string url)
{
var openFilePage = new OpenFilesPage(url);;
_navigationRoot.Navigation.PushModalAsync(new NavigationPage(openFilePage));
}
Эта функция создает новую страницу Xamarin.Forms, передает ей место расположения файла и отображает эту страницу модально (В конструкторе класса App
все вложено в NavigationPage
и сохранено в переменной _navigationRoot
).
Отображаясь модально, она появится поверх всего остального, происходящего в приложении, и никак не отразится на стеке навигации (кроме того, что появится поверх). Конечно ориентация будет на просмотр PDF файла. В реальном приложении необходимо проверить состояние самого приложения – что отображается в настоящий момент (чтобы не было стека модальных окон). Рабочий процесс приложения может потребовать закрыть весь стек и начать сначала или, если используются вкладки, переключиться на новую.
OpenFilesPage
имеет подкласс WebView
с кастомным рендерером для каждой платформы. В этом классе есть свойство место расположения файла, который нужно отобразить. Затем кастомный рендерер отображает его.
Отображение файла кастомным рендерером поможет избежать перехода в специфическое месторасположение файла в iOS. Но опять-таки, это только в этом специфичном исполнении сценария. Важный момент – это потребность класса App в точке входа для доступа iOS проекта.
Итог
В целом, открыть файл из какого-то приложения в Xamarin.Forms приложении не так сложно. Есть некоторые формальности, одна из которых – скорректировать файл Info.plist, чтобы зарегистрировать приложение как способное обрабатывать файлы определенного типа. И необходимость переписать OpenUrl
функцию для iOS приложения.
После этого все зависит от Xamarin.Forms. Необходимо создать точку входа в классе App
, чтобы AppDelegate в iOS мог обратиться к «общей» части кода. Здесь нужно действовать в зависимости от того, что необходимо сделать с файлом. Может понадобиться написание кастомного рендерера для отображения. Или можно все сделать в общем проекте, если не понадобится дополнительный функционал платформы.
Благодарим за перевод
Александр Алексеев — Xamarin-разработчик, фрилансер. Работает с .NET-платформой с 2012 года. Участвовал в разработке системы автоматизации закупок в компании Digamma. C 2015 года ушел во фриланс и перешел на мобильную разработку с использованием Xamarin. В текущее время работает в компании StecPoint над iOS приложением.
Ведет ресурс XamDev.ru и сообщества «Xamarin Developers» в социальных сетях: VK, Facebook, Telegram.
Автор: Microsoft