如何在iOS上打开已下载的文件

3
我们正在使用Xamarin开发移动应用程序。如何在iOS中完成以下操作:
  • 用户从URL下载文件(向REST API发出HTTP请求,该API受Basic身份验证保护,用户名:secretKey)
  • 文件保存到iOS设备上
  • 用户打开文件(允许的格式有jpg、png、pdf、doc、docx、png)
  • 文件在默认应用程序中打开(例如图片查看器)
由于文件操作是特定于平台的,因此这里提供接口定义:
public interface IFileHelper
{
  void DownloadFileAndSave(Models.DocumentModel document);
}

Android实现:

public class FileHelper : IFileHelper
{
  // download file and view status in download manager
  public void DownloadFileAndSave(Models.DocumentModel document)
  {
    DownloadManager dm = (DownloadManager)Android.App.Application.Context.GetSystemService(Context.DownloadService);
    string url = WebApiUtils.GetBaseUrl() + string.Format("Api/v1/Dms/{0}", document.UniqueId);
    DownloadManager.Request request = new Android.App.DownloadManager.Request(Android.Net.Uri.Parse(url)));

    request.AddRequestHeader("Authorization", "Basic " + WebApiUtils.GetEncodedCredentials(Auth.Users.Current));

    var downloadFile = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);
    string path = Path.Combine(downloadFile.AbsolutePath, document.FileName);
    request.SetDestinationUri(Android.Net.Uri.FromFile(new Java.IO.File(path)));
    request.SetMimeType(document.ContentType);  
    request.SetNotificationVisibility(DownloadVisibility.VisibleNotifyCompleted);

    dm.Enqueue(request);
}

在Android系统中,文件只是简单地存储在文件系统中,并且默认安装在任何Android设备上的文件浏览器(即我的文件->设备存储->下载)中,该文件会在与文件MIME类型相对应的默认应用程序中打开。在Android上一切都很好。

Apple iOS实现:

public class FileHelper : IFileHelper
{
  public void DownloadFileAndSave(Models.DocumentModel document)
  {
    WebClient webClient = new WebClient();

    webClient.Headers.Add(HttpRequestHeader.Authorization, "Basic " + WebApiUtils.GetEncodedCredentials(Auth.Users.Current));
    webClient.DownloadDataAsync(new System.Uri(WebApiUtils.GetBaseUrl() + string.Format(Consts.ApiUrls.GetDocument, document.UniqueId)));

    webClient.DownloadDataCompleted += (sender, e) =>
    {
      byte[] content = e.Result;
      string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), document.FileName);

      // doesn't throw exception therefore saved ok
      File.WriteAllBytes(path, content);

      Uri uri = new Uri(String.Format("file://{0}", path));

      // doesn't work.
      Device.OpenUri(uri);
    };
  }
}

有没有其他方法可以用默认应用程序打开下载的文件?如果我打开网址,例如http://example.com/files/file1.png,它会在safari中打开该文件,但我无法在Device.OpenUri中放置Authorization: Basic标头。
我了解到使用WebView加载非Web文档,但您需要将每个文件构建为BundleResource

1
在你的iOS代码中,你注释说没有抛出异常,你能看到路径中的文件吗? - Simon Price
1
另外,不确定你是否看过这个,但是请看一下这里https://forums.xamarin.com/discussion/68919/device-openuri-with-a-pdf-on-ios,这是一个类似于你遇到的问题,我相信OP也在这里解决了这个问题。 - Simon Price
@CodeWarrior 谢谢你提供的链接,我之前错过了。这个解决方案几乎可以用。请看下面我的回答。 - broadband
@CodeWarrior 我在路径中没有看到文件,我只是用 System.IO.File.Exists(path); 进行了测试。 - broadband
你在下面的回答中解决了这个问题吗? - Simon Price
@CodeWarrior 是的,我搞定了。我缺少 iOS 11 的权限,但正如我在答案中提到的,苹果可以返回更合适的错误信息。 - broadband
1个回答

0

正如Code Warrior所评论的那样,有一种方法发布在链接上:https://forums.xamarin.com/discussion/36964/why-is-it-that-nothing-is-working-to-open-an-existing-local-pdf-file-in-the-ios-portion-of-my-pcl

但是保存图像操作不起作用,其他所有操作似乎都可以正常工作。

public void DownloadFileAndSave(Models.DocumentModel document)
{
  WebClient webClient = new WebClient();
  webClient.Headers.Add(HttpRequestHeader.Authorization, "Basic " + WebApiUtils.GetEncodedCredentials(Auth.Users.Current));

  string tempPath = Path.GetTempPath();
  string localFilename = Path.GetFileName(document.FileName);
  string localPath = Path.Combine(tempPath, localFilename);

  webClient.DownloadFileCompleted += (sender, e) =>
  {
    Device.BeginInvokeOnMainThread(() =>
    {
      QLPreviewItemFileSystem prevItem = new QLPreviewItemFileSystem(localFilename, localPath); // ql = quick look
      QLPreviewController previewController = new QLPreviewController()
      {
        DataSource = new PreviewControllerDS(prevItem)
      };
      UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(previewController, true, null);
    });
  };

  // download file
  Uri uri = new System.Uri(WebApiUtils.GetBaseUrl() + string.Format(Consts.ApiUrls.GetDocument, document.UniqueId));
  webClient.DownloadFileAsync(uri, localPath);
}

当触发“保存图像”时,我会得到以下错误:

2017-10-03 13:45:56.797 MyApp.iOS[477:61030] 视频 /private/var/mobile/Containers/Data/Application/33D7139A-53E0-4A2E-8C78-D3D13A2259B0/tmp/water-h2o-md.png 无法保存到照片库:Error Domain=AVFoundationErrorDomain Code=-11828 "无法打开" UserInfo={NSUnderlyingError=0x1c0445d60 {Error Domain=NSOSStatusErrorDomain Code=-12847 "(null)"}, NSLocalizedFailureReason=不支持此媒体格式, NSURL=file:///private/var/mobile/Containers/Data/Application/33D7139A-53E0-4A2E-8C78-D3D13A2259B0/tmp/water-h2o-md.png, NSLocalizedDescription=无法打开}

iOS将图像视为视频?这是iOS的一个错误还是我漏掉了什么。

更新

原来在Info.plist文件中缺少以下权限:

<key>NSPhotoLibraryUsageDescription</key>
<string>Application needs to access photos</string>

<!-- for iOS 11 -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Application needs to access photos</string>

现在保存图片操作正常工作。但是说真的,苹果公司可以返回一个更合适的错误信息,而不是Video image.jpg 无法保存...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接