从 Cloud Storage 下载文件(Apple 平台)

Cloud Storage for Firebase 可让您快速轻松地从 Firebase 提供和管理的 Cloud Storage 存储桶中下载文件。

创建引用

如需下载某个文件,请先为要下载的文件创建一个 Cloud Storage 引用

您可以通过将子路径附加到 Cloud Storage 存储桶的根目录来创建引用,也可以根据指向 Cloud Storage 中的对象的现有 gs://https:// 网址创建引用。

Swift

// Create a reference with an initial file path and name
let pathReference = storage.reference(withPath: "images/stars.jpg")

// Create a reference from a Google Cloud Storage URI
let gsReference = storage.reference(forURL: "gs://<your-firebase-storage-bucket>/images/stars.jpg")

// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
let httpsReference = storage.reference(forURL: "https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg")

Objective-C

// Create a reference with an initial file path and name
FIRStorageReference *pathReference = [storage referenceWithPath:@"images/stars.jpg"];

// Create a reference from a Google Cloud Storage URI
FIRStorageReference *gsReference = [storage referenceForURL:@"gs://<your-firebase-storage-bucket>/images/stars.jpg"];

// Create a reference from an HTTPS URL
// Note that in the URL, characters are URL escaped!
FIRStorageReference *httpsReference = [storage referenceForURL:@"https://firebasestorage.googleapis.com/b/bucket/o/images%20stars.jpg"];
  

下载文件

有了引用之后,可通过三种方法从 Cloud Storage 中下载文件:

  1. 下载到内存中的 NSData
  2. 下载到表示设备上某个文件的 NSURL
  3. 生成一个表示在线文件的 NSURL

下载至内存

使用 dataWithMaxSize:completion: 方法将文件下载到内存中的 NSData 对象。这是快速下载文件的最简单方法,但它必须将文件的全部内容加载到内存中。 如果您请求下载的文件大于应用的可用内存,应用将会崩溃。为了防止出现内存问题,请务必将大小上限设置为已知您的应用可以处理的数值,或使用其他下载方法。

Swift

// Create a reference to the file you want to download
let islandRef = storageRef.child("images/island.jpg")

// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
islandRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
  if let error = error {
    // Uh-oh, an error occurred!
  } else {
    // Data for "images/island.jpg" is returned
    let image = UIImage(data: data!)
  }
}
    

Objective-C

// Create a reference to the file you want to download
FIRStorageReference *islandRef = [storageRef child:@"images/island.jpg"];

// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
[islandRef dataWithMaxSize:1 * 1024 * 1024 completion:^(NSData *data, NSError *error){
  if (error != nil) {
    // Uh-oh, an error occurred!
  } else {
    // Data for "images/island.jpg" is returned
    UIImage *islandImage = [UIImage imageWithData:data];
  }
}];
    

下载至本地文件

writeToFile:completion: 方法可将文件直接下载至本地设备。如果用户希望离线时可以访问文件或希望在不同的应用中共享文件,请使用这种方法。writeToFile:completion: 会返回一个 FIRStorageDownloadTask,您可以使用它来管理下载并监控下载状态。

Swift

// Create a reference to the file you want to download
let islandRef = storageRef.child("images/island.jpg")

// Create local filesystem URL
let localURL = URL(string: "path/to/image")!

// Download to the local filesystem
let downloadTask = islandRef.write(toFile: localURL) { url, error in
  if let error = error {
    // Uh-oh, an error occurred!
  } else {
    // Local file URL for "images/island.jpg" is returned
  }
}
    

Objective-C

// Create a reference to the file you want to download
FIRStorageReference *islandRef = [storageRef child:@"images/island.jpg"];

// Create local filesystem URL
NSURL *localURL = [NSURL URLWithString:@"path/to/image"];

// Download to the local filesystem
FIRStorageDownloadTask *downloadTask = [islandRef writeToFile:localURL completion:^(NSURL *URL, NSError *error){
  if (error != nil) {
    // Uh-oh, an error occurred!
  } else {
    // Local file URL for "images/island.jpg" is returned
  }
}];
    

如果要主动管理下载,您可以使用 writeToFile: 方法并观察下载任务,而不是使用完成处理程序。如需了解详情,请参阅管理下载

生成下载网址

如果您已经有了基于网址的下载基础架构,或者只需要一个网址用于共享,可通过对 Cloud Storage 引用调用 downloadURLWithCompletion: 方法来获取文件的下载网址。

Swift

// Create a reference to the file you want to download
let starsRef = storageRef.child("images/stars.jpg")

// Fetch the download URL
starsRef.downloadURL { url, error in
  if let error = error {
    // Handle any errors
  } else {
    // Get the download URL for 'images/stars.jpg'
  }
}
    

Objective-C

// Create a reference to the file you want to download
FIRStorageReference *starsRef = [storageRef child:@"images/stars.jpg"];

// Fetch the download URL
[starsRef downloadURLWithCompletion:^(NSURL *URL, NSError *error){
  if (error != nil) {
    // Handle any errors
  } else {
    // Get the download URL for 'images/stars.jpg'
  }
}];
    

通过 FirebaseUI 下载图片

FirebaseUI 提供简单、可定制且适合生产环境的原生移动绑定,以消除样板代码并促进遵循 Google 最佳实践。借助与 SDWebImage 的集成,您可以使用 FirebaseUI 快速轻松地下载、缓存和显示 Cloud Storage 中的图片。

首先,将 FirebaseUI 添加到您的 Podfile 文件:

pod 'FirebaseStorageUI'

然后,您可以直接将 Cloud Storage 中的图片加载到 UIImageView

Swift

// Reference to an image file in Firebase Storage
let reference = storageRef.child("images/stars.jpg")

// UIImageView in your ViewController
let imageView: UIImageView = self.imageView

// Placeholder image
let placeholderImage = UIImage(named: "placeholder.jpg")

// Load the image using SDWebImage
imageView.sd_setImage(with: reference, placeholderImage: placeholderImage)
    

Objective-C

// Reference to an image file in Firebase Storage
FIRStorageReference *reference = [storageRef child:@"images/stars.jpg"];

// UIImageView in your ViewController
UIImageView *imageView = self.imageView;

// Placeholder image
UIImage *placeholderImage;

// Load the image using SDWebImage
[imageView sd_setImageWithStorageReference:reference placeholderImage:placeholderImage];
    

管理下载

除了启动下载,您还可以使用 pauseresumecancel 方法来暂停、恢复和取消下载。这些方法会引发您可以观察的 pauseresumecancel 事件。

Swift

// Start downloading a file
let downloadTask = storageRef.child("images/mountains.jpg").write(toFile: localFile)

// Pause the download
downloadTask.pause()

// Resume the download
downloadTask.resume()

// Cancel the download
downloadTask.cancel()
    

Objective-C

// Start downloading a file
FIRStorageDownloadTask *downloadTask = [[storageRef child:@"images/mountains.jpg"] writeToFile:localFile];

// Pause the download
[downloadTask pause];

// Resume the download
[downloadTask resume];

// Cancel the download
[downloadTask cancel];
    

监控下载进度

您可以向 FIRStorageDownloadTask 附加观察者 (observer),以便监控下载的进度。添加观察者后会返回一个 FIRStorageHandle,它可用于移除此观察者。

Swift

// Add a progress observer to a download task
let observer = downloadTask.observe(.progress) { snapshot in
  // A progress event occurred
}
    

Objective-C

// Add a progress observer to a download task
FIRStorageHandle observer = [downloadTask observeStatus:FIRStorageTaskStatusProgress
                                                handler:^(FIRStorageTaskSnapshot *snapshot) {
                                                  // A progress event occurred
                                                }];
    

这些观察者可以注册到一个 FIRStorageTaskStatus 事件:

FIRStorageTaskStatus 事件 典型用法
FIRStorageTaskStatusResume 此事件在任务开始或恢复下载时触发,且通常与 FIRStorageTaskStatusPause 事件结合使用。
FIRStorageTaskStatusProgress 每次从 Cloud Storage 下载数据时,此事件都会触发,并可用于为下载进度指示器提供所需数据。
FIRStorageTaskStatusPause 每次下载被暂停时,此事件都会触发,通常与 FIRStorageTaskStatusResume 事件结合使用。
FIRStorageTaskStatusSuccess 此事件会在下载成功完成时触发。
FIRStorageTaskStatusFailure 此事件会在下载失败时触发。请检查错误以确定失败原因。

当有事件发生时,系统将传回 FIRStorageTaskSnapshot 对象。此快照是事件发生时的任务视图,该视图不可改变。 此对象包含以下属性:

属性 类型 说明
progress NSProgress 包含下载进度的 NSProgress 对象。
error NSError 下载期间发生的错误(如果有)。
metadata FIRStorageMetadata 下载时为 nil
task FIRStorageDownloadTask 快照所对应的任务,可用于管理任务(使用 pause 暂停、使用 resume 继续、使用 cancel 取消)。
reference FIRStorageReference 此任务的来源引用。

您可以逐个移除观察者,也可以按状态移除或是全部移除。

Swift

// Create a task listener handle
let observer = downloadTask.observe(.progress) { snapshot in
// A progress event occurred
}

// Remove an individual observer
downloadTask.removeObserver(withHandle: observer)

// Remove all observers of a particular status
downloadTask.removeAllObservers(for: .progress)

// Remove all observers
downloadTask.removeAllObservers()
    

Objective-C

// Create a task listener handle
FIRStorageHandle observer = [downloadTask observeStatus:FIRStorageTaskStatusProgress
                                                handler:^(FIRStorageTaskSnapshot *snapshot) {
                                                  // A progress event occurred
                                                }];

// Remove an individual observer
[downloadTask removeObserverWithHandle:observer];

// Remove all observers of a particular status
[downloadTask removeAllObserversForStatus:FIRStorageTaskStatusProgress];

// Remove all observers
[downloadTask removeAllObservers];
    

为了防止内存泄露,所有观测器在发生 FIRStorageTaskStatusSuccessFIRStorageTaskStatusFailure 后都会被移除。

处理错误

导致下载出错的原因有很多,包括文件不存在,或者用户不具备访问相应文件的权限。如需了解有关错误的详细信息,请参阅文档的处理错误部分。

完整示例

下面是下载到本地文件的完整示例(包含错误处理):

Swift

// Create a reference to the file we want to download
let starsRef = storageRef.child("images/stars.jpg")

// Start the download (in this case writing to a file)
let downloadTask = storageRef.write(toFile: localURL)

// Observe changes in status
downloadTask.observe(.resume) { snapshot in
  // Download resumed, also fires when the download starts
}

downloadTask.observe(.pause) { snapshot in
  // Download paused
}

downloadTask.observe(.progress) { snapshot in
  // Download reported progress
  let percentComplete = 100.0 * Double(snapshot.progress!.completedUnitCount)
    / Double(snapshot.progress!.totalUnitCount)
}

downloadTask.observe(.success) { snapshot in
  // Download completed successfully
}

// Errors only occur in the "Failure" case
downloadTask.observe(.failure) { snapshot in
  guard let errorCode = (snapshot.error as? NSError)?.code else {
    return
  }
  guard let error = StorageErrorCode(rawValue: errorCode) else {
    return
  }
  switch (error) {
  case .objectNotFound:
    // File doesn't exist
    break
  case .unauthorized:
    // User doesn't have permission to access file
    break
  case .cancelled:
    // User cancelled the download
    break

  /* ... */

  case .unknown:
    // Unknown error occurred, inspect the server response
    break
  default:
    // Another error occurred. This is a good place to retry the download.
    break
  }
}
    

Objective-C

// Create a reference to the file we want to download
FIRStorageReference *starsRef = [storageRef child:@"images/stars.jpg"];

// Start the download (in this case writing to a file)
FIRStorageDownloadTask *downloadTask = [storageRef writeToFile:localURL];

// Observe changes in status
[downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Download resumed, also fires when the download starts
}];

[downloadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Download paused
}];

[downloadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Download reported progress
  double percentComplete = 100.0 * (snapshot.progress.completedUnitCount) / (snapshot.progress.totalUnitCount);
}];

[downloadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
  // Download completed successfully
}];

// Errors only occur in the "Failure" case
[downloadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
  if (snapshot.error != nil) {
    switch (snapshot.error.code) {
      case FIRStorageErrorCodeObjectNotFound:
        // File doesn't exist
        break;

      case FIRStorageErrorCodeUnauthorized:
        // User doesn't have permission to access file
        break;

      case FIRStorageErrorCodeCancelled:
        // User canceled the upload
        break;

      /* ... */

      case FIRStorageErrorCodeUnknown:
        // Unknown error occurred, inspect the server response
        break;
    }
  }
}];
    

对于存储在 Cloud Storage 中的文件,您还可以获取和更新元数据