Просмотрщик файлов для 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
Другие вопросы по тегам