【问题标题】:Xamarin Forms: Open downloaded file in default Android/iOS applicationXamarin Forms:在默认 Android/iOS 应用程序中打开下载的文件
【发布时间】:2020-01-10 17:34:45
【问题描述】:

我正在使用 Xamarin 表单。我想下载 jpg 文件(已完成),然后在 Android/iOS 上的默认应用程序中打开该 jpg(用这张照片打开照片浏览器)。当然照片是单个示例,我想在默认应用程序中打开任何文件。

我找到了几个纯原生解决方案,但我的应用程序设计为跨平台。我虽然可以使用 Xamarin.Essentials 包中的 Launcher,但显然我不能。

如何做到这一点?

【问题讨论】:

    标签: xamarin.forms


    【解决方案1】:

    你可以试试Xamarin.Essentials: Launcher:

    var fn = "File.txt";
    var file = Path.Combine(FileSystem.CacheDirectory, fn);
    File.WriteAllText(file, "Hello World");
    
    await Launcher.OpenAsync(new OpenFileRequest
    {
        File = new ReadOnlyFile(file)
    });
    

    【讨论】:

    • 我无法使用,因为 Android 上的错误 file:////data/user/0/mypackagename/files/.local/share/Screenshot.jpg exposed beyond app through Intent.getData() 和 iOS 上的 canOpenURL: failed for URL: ** -- file:///" - error: "This app is not allowed to query for scheme file 错误
    【解决方案2】:

    我找到了几个纯原生解决方案

    在另一个应用程序中打开一些东西非常接近移动应用程序的系统,并且有一些事情需要考虑,这取决于平台。通常,移动应用程序在沙盒中运行,对周围系统的访问非常有限。特别是这意味着,如果您将文件下载到应用程序的沙箱中,则不允许其他应用程序(本地查看器)访问该文件。

    在 Android 上,您可以将文件复制到共享空间(请参阅Application.Context.GetExternalFilesDir(null))然后打开它。使用 Essentials 可能会实现这一点,但我不太确定,但由于我们现在仍然在 Android 平台上,所以无论如何您现在都可以创建一个意图。

    在 iOS 上,您可以在应用程序中创建控制器(例如,QLPreviewController 用于预览文件)以访问沙箱中的项目。根据控制器的类型(例如UIActivityViewController),他们可能会打开其他应用程序。

    如何独立使用这个平台?

    由于您正在编写一个独立于平台的应用程序,因此您必须注意为依赖于平台的工作调用正确的类。有几种方法可以实现这一目标

    • 使用DependencyService
    • 使用真正的依赖注入框架
    • 在平台相关项目中使用带有初始化的抽象基类

    DependencyService

    要使用 Xamarin.Forms DependencyService,您需要两件事

    • 您要实现的功能的接口
    • 每个平台一个实现

    假设您有一个简单的界面来共享文件

    public IShareFile
    {
        void ShareFile(string fileName);
    }
    

    您可以在每个平台上实现此接口的实现并将DependencyAttribute 添加到程序集。例如对于 iOS:

    [assembly: Dependency(typeof(MyApp.iOS.DeviceOrientationService))]
    namespace MyApp.iOS
    {
        public class ShareFile : IShareFile
        {
            public void Share(string fileName)
            {
                // implementation goes here
            }
        }
    }
    

    Android 的通用脚手架是相同的,只是实现方式不同。

    使用真正的依赖注入框架

    基本上是一样的。不过,您可以跳过DependencyAttribute。为了使实现可用,您必须从特定于平台的代码中获取 DI 容器,这可能很棘手。这可能是单个依赖项的过冲,但如果您仍然使用 DI 容器并且存在 X 个依赖项,那么这可能是值得的。

    使用抽象基类

    为你的项目添加一个抽象基类

    public abstract class ShareFile
    {
        public static ShareFile Instance { get; protected set; }
    
        public abstract void Share(string fileName);
    }
    

    在平台特定项目的实现中,添加一个Init() 方法

    internal class ShareFileImpl : ShareFile
    {
        public static void Init()
        {
            ShareFile.Instance = new ShareFileImpl();
        }
    
        public void Share(string fileName)
        {
            // implementation goes here
        }
    }
    

    必须从您的平台特定代码调用此 init 方法。最有可能在初始化期间。然后可以通过它的抽象从您的平台无关代码访问该实现(当然,您只会看到抽象,添加到ShareFileImpl 的公共方法不会从您的平台无关代码中可见)。

    ShareFile.Instance.Share(fileName);
    

    抽象类方法和依赖注入的组合也是可以想象的。在 DI 框架中注册您的类时,您可以像这样注册平台实例

    container.RegisterInstance<ShareFile>(ShareFile.Instance);
    

    通过这种方式,您可以利用 DI 容器功能(例如构造函数注入),同时避免在您的平台特定项目中使用 DI 容器的麻烦。缺点是,您仍然需要从您的平台特定代码中调用 ShareFileImpl.Init()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多