Просмотрщик файлов для MAUI
Когда мое приложение было на Xamarin, я использовал службу зависимостей для открытия PDF-файлов и офисных файлов с помощью PresentViewController:
previewController.DataSource = new(directory, filename, filename);
controller.PresentViewController(previewController, true, null);
Я думал, что Лаунчер - это замена Мауи.
Launcher.Default.OpenAsync(new OpenFileRequest(*title*, new ReadOnlyFile(*filePath*))
Office установлен на моем Mac. С Мауи я получаю странные результаты на MacOS. Вместо открытия документа появляется следующее:
Нажатие на это всплывающее окно ничего не дает. Редактировать расширения... мне особо нечего делать
В документации Launcher указано, что это должно работать.
В нем говорится, что он «автоматически определяет тип файла (MIME) и открывает приложение по умолчанию для этого типа файла», что и сделал Xamarin. Однако мне никогда не приходилось возиться с MIME.
Любопытно, что ответ в этом посте использует App Store для открытия файлов. Хм??
Мое приложение Xamarin на iPad запускает PDF-файлы и офисные документы на одном экране предварительного просмотра, даже если соответствующие приложения не установлены. Вызов MAUI в Launcher просто завершается неудачей.
Тот же код Maui Launcher в Windows работает. Он открывает соответствующее приложение и передает в него файл. (например, docx открывает Word, а затем Word вставляет в него документ.)
Как обстоят дела с продукцией Apple? Как заставить работать Launcher или какой-либо другой механизм предварительного просмотра? Должны ли мы использовать код UIKit для замены DependencyService таким образом ?
1 ответ
Это решение предназначено только для доступа только для чтения к файлам, которые я пытался открыть с помощью Launcher. Хотя это решение доступно только для чтения, оно может открывать самые разные типы файлов. Если вам нужно чтение/запись, я до сих пор не знаю, как использовать Launcher ни для MACATALYST, ни для iOS.
Замена MAUI для службы зависимостей Xamarin называется условным кодом для конкретной платформы . Сочетание старого с новым дает мне то, что мне нужно. Например, у меня есть связанный с командой метод OpenSelectedFile в моей ViewModel, который содержит этот фрагмент:
#if (IOS || MACCATALYST)
AppleFileHandler.OpenFile(fileAndPath);
#elif ANDROID
// unkown - in Xamarin we didn't support Android. We'd like to for MAUI.
#else
var roFile = new ReadOnlyFile(fileAndPath);
ret = await Launcher.Default.OpenAsync(new OpenFileRequest(roFile.FileName, roFile));
#endif
AppleFileHandler — это то, что я написал, чтобы ограничить сложность приведенных выше утверждений. Большую часть кода я взял из своей службы зависимостей Xamarin, которая была написана около 8 лет назад и до сих пор работает. (Примечание: я до сих пор не знаю, что такое эквивалент для Android, но Launcher отлично работает в Windows.)
#if (IOS || MACCATALYST)
using QuickLook;
using UIKit;
public class AppleFileHandler
{
public static void OpenFile(string fileName)
{
var fileInfo = new FileInfo(fileName);
using (QLPreviewController previewController = new())
{
previewController.DataSource = new PreviewControllerDataSource(Path.Combine(fileInfo.DirectoryName, fileInfo.Name), fileInfo.Name);
UINavigationController controller = FindNavigationController();
controller?.PresentViewController(previewController, true, null);
controller = null;
}
}
private static UINavigationController FindNavigationController()
{
foreach(UIWindow window in UIApplication.SharedApplication.Windows)
{
if (window.RootViewController.NavigationController != null)
return window.RootViewController.NavigationController;
else
{
UINavigationController value = CheckSubs(window.RootViewController.ChildViewControllers);
if (value != null)
return value;
}
}
return new UINavigationController();
}
private static UINavigationController CheckSubs(UIViewController[] controllers)
{
foreach(UIViewController controller in controllers)
{
if (controller.NavigationController != null)
return controller.NavigationController;
else
{
UINavigationController value = CheckSubs(controller.ChildViewControllers);
if (value != null)
return value;
}
return null;
}
return new UINavigationController();
}
}
#endif
Приведенный выше код зависит от следующих двух классов. Насколько я понимаю, этот код может находиться в папке соответствующей платформы или снаружи, как у меня, с операторами препроцессора.
#if (IOS || MACCATALYST)
using Foundation;
using QuickLook;
public class DocumentItem : QLPreviewItem
{
private string title;
private string url;
public DocumentItem(string title, string url)
{
this.title = title;
this.url = url;
}
public override string PreviewItemTitle => title;
public override NSUrl PreviewItemUrl => NSUrl.FromFilename(url);
}
#endif
и
using System;
#if (IOS || MACCATALYST)
using QuickLook;
public class PreviewControllerDataSource : QLPreviewControllerDataSource
{
private string url;
private string fileName;
public PreviewControllerDataSource(string url, string fileName)
{
this.url = url;
this.fileName = fileName;
}
public override IQLPreviewItem GetPreviewItem(QLPreviewController controller, nint index)
{
return new DocumentItem(fileName, url);
}
public override nint PreviewItemCount(QLPreviewController controller)
{
return 1;
}
}
#endif