StorageReference.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. // Copyright 2022 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import Foundation
  15. import FirebaseStorageObjC
  16. /**
  17. * StorageReference represents a reference to a Google Cloud Storage object. Developers can
  18. * upload and download objects, as well as get/set object metadata, and delete an object at the
  19. * path.
  20. * @see https://cloud.google.com/storage/
  21. */
  22. @objc(FIRStorageReference) open class StorageReference: NSObject {
  23. // MARK: - Public APIs
  24. /**
  25. * The Storage service object which created this reference.
  26. */
  27. @objc public let storage: Storage
  28. /**
  29. * The name of the Google Cloud Storage bucket associated with this reference,
  30. * in gs://bucket/path/to/object.txt, the bucket would be: 'bucket'
  31. */
  32. @objc public let bucket: String
  33. /**
  34. * The full path to this object, not including the Google Cloud Storage bucket.
  35. * In gs://bucket/path/to/object.txt, the full path would be: 'path/to/object.txt'
  36. */
  37. @objc public let fullPath: String
  38. /**
  39. * The short name of the object associated with this reference,
  40. * in gs://bucket/path/to/object.txt, the name of the object would be: 'object.txt'
  41. */
  42. @objc public let name: String
  43. /**
  44. * Creates a new StorageReference pointing to the root object.
  45. * @return A new StorageReference pointing to the root object.
  46. */
  47. @objc open func root() -> StorageReference {
  48. return StorageReference(impl: impl.root(), storage: storage)
  49. }
  50. /**
  51. * Creates a new StorageReference pointing to the parent of the current reference
  52. * or nil if this instance references the root location.
  53. * For example:
  54. * path = foo/bar/baz parent = foo/bar
  55. * path = foo parent = (root)
  56. * path = (root) parent = nil
  57. * @return A new StorageReference pointing to the parent of the current reference.
  58. */
  59. @objc open func parent() -> StorageReference? {
  60. guard let parent = impl.parent() else {
  61. return nil
  62. }
  63. return StorageReference(impl: parent, storage: storage)
  64. }
  65. /**
  66. * Creates a new StorageReference pointing to a child object of the current reference.
  67. * path = foo child = bar newPath = foo/bar
  68. * path = foo/bar child = baz ntask.impl.snapshotwPath = foo/bar/baz
  69. * All leading and trailing slashes will be removed, and consecutive slashes will be
  70. * compressed to single slashes. For example:
  71. * child = /foo/bar newPath = foo/bar
  72. * child = foo/bar/ newPath = foo/bar
  73. * child = foo///bar newPath = foo/bar
  74. * @param path Path to append to the current path.
  75. * @return A new StorageReference pointing to a child location of the current reference.
  76. */
  77. @objc(child:) open func child(_ path: String) -> StorageReference {
  78. return StorageReference(impl: impl.child(path), storage: storage)
  79. }
  80. // MARK: - Uploads
  81. /**
  82. * Asynchronously uploads data to the currently specified StorageReference,
  83. * without additional metadata.
  84. * This is not recommended for large files, and one should instead upload a file from disk.
  85. * @param uploadData The Data to upload.
  86. * @param metadata StorageMetadata containing additional information (MIME type, etc.)
  87. * about the object being uploaded.
  88. * @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
  89. */
  90. @objc(putData:metadata:)
  91. @discardableResult
  92. open func putData(_ uploadData: Data, metadata: StorageMetadata? = nil) -> StorageUploadTask {
  93. return StorageUploadTask(impl.put(uploadData, metadata: metadata?.impl))
  94. }
  95. /**
  96. * Asynchronously uploads data to the currently specified StorageReference.
  97. * This is not recommended for large files, and one should instead upload a file from disk.
  98. * @param uploadData The Data to upload.
  99. * @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
  100. */
  101. @objc(putData:) @discardableResult open func __putData(_ uploadData: Data) -> StorageUploadTask {
  102. return StorageUploadTask(impl.put(uploadData))
  103. }
  104. /**
  105. * Asynchronously uploads data to the currently specified StorageReference.
  106. * This is not recommended for large files, and one should instead upload a file from disk.
  107. * @param uploadData The Data to upload.
  108. * @param metadata StorageMetadata containing additional information (MIME type, etc.)
  109. * about the object being uploaded.
  110. * @param completion A completion block that either returns the object metadata on success,
  111. * or an error on failure.
  112. * @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
  113. */
  114. @objc(putData:metadata:completion:) @discardableResult
  115. open func putData(_ uploadData: Data,
  116. metadata: StorageMetadata? = nil,
  117. completion: ((_: StorageMetadata?, _: Error?) -> Void)?) -> StorageUploadTask {
  118. return StorageUploadTask(impl.put(uploadData, metadata: metadata?.impl) { impl, error in
  119. if let completion = completion {
  120. self.adaptMetadataCallback(completion: completion)(impl, error)
  121. }
  122. })
  123. }
  124. /**
  125. * Asynchronously uploads a file to the currently specified StorageReference.
  126. * @param fileURL A URL representing the system file path of the object to be uploaded.
  127. * @param metadata StorageMetadata containing additional information (MIME type, etc.)
  128. * about the object being uploaded.
  129. * @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
  130. */
  131. @objc(putFile:metadata:) @discardableResult
  132. open func putFile(from fileURL: URL, metadata: StorageMetadata? = nil) -> StorageUploadTask {
  133. return StorageUploadTask(impl.putFile(fileURL, metadata: metadata?.impl))
  134. }
  135. /**
  136. * Asynchronously uploads a file to the currently specified StorageReference,
  137. * without additional metadata.
  138. * @param fileURL A URL representing the system file path of the object to be uploaded.
  139. * @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
  140. */
  141. @objc(putFile:) @discardableResult open func __putFile(from fileURL: URL) -> StorageUploadTask {
  142. return StorageUploadTask(impl.putFile(fileURL))
  143. }
  144. /**
  145. * Asynchronously uploads a file to the currently specified StorageReference.
  146. * @param fileURL A URL representing the system file path of the object to be uploaded.
  147. * @param metadata StorageMetadata containing additional information (MIME type, etc.)
  148. * about the object being uploaded.
  149. * @param completion A completion block that either returns the object metadata on success,
  150. * or an error on failure.
  151. * @return An instance of StorageUploadTask, which can be used to monitor or manage the upload.
  152. */
  153. @objc(putFile:metadata:completion:) @discardableResult
  154. open func putFile(from fileURL: URL,
  155. metadata: StorageMetadata? = nil,
  156. completion: ((_: StorageMetadata?, _: Error?) -> Void)?) -> StorageUploadTask {
  157. return StorageUploadTask(impl.putFile(fileURL, metadata: metadata?.impl) { impl, error in
  158. if let completion = completion {
  159. self.adaptMetadataCallback(completion: completion)(impl, error)
  160. }
  161. })
  162. }
  163. // MARK: - Downloads
  164. /**
  165. * Asynchronously downloads the object at the StorageReference to an Data object in memory.
  166. * An Data of the provided max size will be allocated, so ensure that the device has enough free
  167. * memory to complete the download. For downloading large files, writeToFile may be a better option.
  168. * @param maxSize The maximum size in bytes to download. If the download exceeds this size,
  169. * the task will be cancelled and an error will be returned.
  170. * @param completion A completion block that either returns the object data on success,
  171. * or an error on failure.
  172. * @return An StorageDownloadTask that can be used to monitor or manage the download.
  173. */
  174. @objc(dataWithMaxSize:completion:) @discardableResult
  175. open func getData(maxSize: Int64,
  176. completion: @escaping ((_: Data?, _: Error?) -> Void)) -> StorageDownloadTask {
  177. return StorageDownloadTask(impl.data(withMaxSize: maxSize, completion: completion))
  178. }
  179. /**
  180. * Asynchronously retrieves a long lived download URL with a revokable token.
  181. * This can be used to share the file with others, but can be revoked by a developer
  182. * in the Firebase Console.
  183. * @param completion A completion block that either returns the URL on success,
  184. * or an error on failure.
  185. */
  186. @objc(downloadURLWithCompletion:)
  187. open func downloadURL(completion: @escaping ((_: URL?, _: Error?) -> Void)) {
  188. impl.downloadURL(completion: completion)
  189. }
  190. #if compiler(>=5.5) && canImport(_Concurrency)
  191. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  192. /**
  193. * Asynchronously retrieves a long lived download URL with a revokable token.
  194. * This can be used to share the file with others, but can be revoked by a developer
  195. * in the Firebase Console.
  196. * @returns completion The URL on success.
  197. */
  198. open func downloadURL() async throws -> URL {
  199. return try await impl.downloadURL()
  200. }
  201. #endif // compiler(>=5.5) && canImport(_Concurrency)
  202. /**
  203. * Asynchronously downloads the object at the current path to a specified system filepath.
  204. * @param fileURL A file system URL representing the path the object should be downloaded to.
  205. * @return An StorageDownloadTask that can be used to monitor or manage the download.
  206. */
  207. @objc(writeToFile:) @discardableResult
  208. open func write(toFile fileURL: URL) -> StorageDownloadTask {
  209. return StorageDownloadTask(impl.write(toFile: fileURL))
  210. }
  211. /**
  212. * Asynchronously downloads the object at the current path to a specified system filepath.
  213. * @param fileURL A file system URL representing the path the object should be downloaded to.
  214. * @param completion A completion block that fires when the file download completes.
  215. * Returns an URL pointing to the file path of the downloaded file on success,
  216. * or an error on failure.
  217. * @return An StorageDownloadTask that can be used to monitor or manage the download.
  218. */
  219. @objc(writeToFile:completion:) @discardableResult
  220. open func write(toFile fileURL: URL,
  221. completion: ((_: URL?, _: Error?) -> Void)?) -> StorageDownloadTask {
  222. return StorageDownloadTask(impl.write(toFile: fileURL, completion: completion))
  223. }
  224. // MARK: - List Support
  225. /**
  226. * List all items (files) and prefixes (folders) under this StorageReference.
  227. *
  228. * This is a helper method for calling list() repeatedly until there are no more results.
  229. * Consistency of the result is not guaranteed if objects are inserted or removed while this
  230. * operation is executing. All results are buffered in memory.
  231. *
  232. * `listAll(completion:)` is only available for projects using Firebase Rules Version 2.
  233. *
  234. * @param completion A completion handler that will be invoked with all items and prefixes under
  235. * the current StorageReference.
  236. */
  237. @objc(listAllWithCompletion:)
  238. open func listAll(completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
  239. impl.listAll { listResult, error in
  240. if error != nil {
  241. completion(nil, error)
  242. } else {
  243. completion(StorageListResult(listResult), error)
  244. }
  245. }
  246. }
  247. #if compiler(>=5.5) && canImport(_Concurrency)
  248. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  249. /**
  250. * List all items (files) and prefixes (folders) under this StorageReference.
  251. *
  252. * This is a helper method for calling list() repeatedly until there are no more results.
  253. * Consistency of the result is not guaranteed if objects are inserted or removed while this
  254. * operation is executing. All results are buffered in memory.
  255. *
  256. * `listAll()` is only available for projects using Firebase Rules Version 2.
  257. *
  258. * @returns completion All items and prefixes under the current StorageReference.
  259. */
  260. open func listAll() async throws -> StorageListResult {
  261. return try await StorageListResult(impl.listAll())
  262. }
  263. #endif // compiler(>=5.5) && canImport(_Concurrency)
  264. /**
  265. * List up to `maxResults` items (files) and prefixes (folders) under this StorageReference.
  266. *
  267. * "/" is treated as a path delimiter. Firebase Storage does not support unsupported object
  268. * paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be
  269. * filtered.
  270. *
  271. * `list(maxResults:completion:)` is only available for projects using Firebase Rules Version 2.
  272. *
  273. * @param maxResults The maximum number of results to return in a single page. Must be greater
  274. * than 0 and at most 1000.
  275. * @param completion A completion handler that will be invoked with up to maxResults items and
  276. * prefixes under the current StorageReference.
  277. */
  278. @objc(listWithMaxResults:completion:)
  279. open func list(maxResults: Int64,
  280. completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
  281. impl.list(withMaxResults: maxResults) { listResult, error in
  282. if error != nil {
  283. completion(nil, error)
  284. } else {
  285. completion(StorageListResult(listResult), error)
  286. }
  287. }
  288. }
  289. /**
  290. * Resumes a previous call to list(maxResults:completion:)`, starting after a pagination token.
  291. * Returns the next set of items (files) and prefixes (folders) under this StorageReference.
  292. *
  293. * "/" is treated as a path delimiter. Firebase Storage does not support unsupported object
  294. * paths that end with "/" or contain two consecutive "/"s. All invalid objects in GCS will be
  295. * filtered.
  296. *
  297. * `list(maxResults:pageToken:completion:)`is only available for projects using Firebase Rules
  298. * Version 2.
  299. *
  300. * @param maxResults The maximum number of results to return in a single page. Must be greater
  301. * than 0 and at most 1000.
  302. * @param pageToken A page token from a previous call to list.
  303. * @param completion A completion handler that will be invoked with the next items and prefixes
  304. * under the current StorageReference.
  305. */
  306. @objc(listWithMaxResults:pageToken:completion:)
  307. open func list(maxResults: Int64,
  308. pageToken: String,
  309. completion: @escaping ((_: StorageListResult?, _: Error?) -> Void)) {
  310. impl.list(withMaxResults: maxResults, pageToken: pageToken) { listResult, error in
  311. if error != nil {
  312. completion(nil, error)
  313. } else {
  314. completion(StorageListResult(listResult), error)
  315. }
  316. }
  317. }
  318. // MARK: - Metadata Operations
  319. /**
  320. * Retrieves metadata associated with an object at the current path.
  321. * @param completion A completion block which returns the object metadata on success,
  322. * or an error on failure.
  323. */
  324. @objc(metadataWithCompletion:)
  325. open func getMetadata(completion: @escaping ((_: StorageMetadata?, _: Error?) -> Void)) {
  326. impl.metadata { impl, error in
  327. self.adaptMetadataCallback(completion: completion)(impl, error)
  328. }
  329. }
  330. #if compiler(>=5.5) && canImport(_Concurrency)
  331. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  332. /**
  333. * Retrieves metadata associated with an object at the current path.
  334. * @returns The object metadata on success.
  335. */
  336. open func getMetadata() async throws -> StorageMetadata {
  337. return try await StorageMetadata(impl: impl.metadata())
  338. }
  339. #endif // compiler(>=5.5) && canImport(_Concurrency)
  340. /**
  341. * Updates the metadata associated with an object at the current path.
  342. * @param metadata An StorageMetadata object with the metadata to update.
  343. * @param completion A completion block which returns the StorageMetadata on success,
  344. * or an error on failure.
  345. */
  346. @objc(updateMetadata:completion:)
  347. open func updateMetadata(_ metadata: StorageMetadata,
  348. completion: ((_: StorageMetadata?, _: Error?) -> Void)?) {
  349. impl.update(metadata.impl) { impl, error in
  350. if let completion = completion {
  351. self.adaptMetadataCallback(completion: completion)(impl, error)
  352. }
  353. }
  354. }
  355. #if compiler(>=5.5) && canImport(_Concurrency)
  356. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  357. /**
  358. * Updates the metadata associated with an object at the current path.
  359. * @param metadata An StorageMetadata object with the metadata to update.
  360. * @returns The object metadata on success.
  361. */
  362. open func updateMetadata(_ metadata: StorageMetadata) async throws -> StorageMetadata {
  363. return try await StorageMetadata(impl: impl.update(metadata.impl))
  364. }
  365. #endif // compiler(>=5.5) && canImport(_Concurrency)
  366. private func adaptMetadataCallback(completion: @escaping (StorageMetadata?, Error?) -> Void) ->
  367. (_: FIRIMPLStorageMetadata?, _: Error?)
  368. -> Void {
  369. return { (impl: FIRIMPLStorageMetadata?, error: Error?) in
  370. if let impl = impl {
  371. completion(StorageMetadata(impl: impl), error)
  372. } else {
  373. completion(nil, error)
  374. }
  375. }
  376. }
  377. // MARK: - Delete
  378. /**
  379. * Deletes the object at the current path.
  380. * @param completion A completion block which returns nil on success, or an error on failure.
  381. */
  382. @objc(deleteWithCompletion:)
  383. open func delete(completion: ((_: Error?) -> Void)?) {
  384. impl.delete(completion: completion)
  385. }
  386. #if compiler(>=5.5) && canImport(_Concurrency)
  387. @available(iOS 13, tvOS 13, macOS 10.15, watchOS 8, *)
  388. /**
  389. * Deletes the object at the current path.
  390. */
  391. open func delete() async throws {
  392. return try await impl.delete()
  393. }
  394. #endif // compiler(>=5.5) && canImport(_Concurrency)
  395. // MARK: - NSObject overrides
  396. @objc open func copy(_ zone: NSZone) -> StorageReference {
  397. return StorageReference(impl.copy() as! FIRIMPLStorageReference)
  398. }
  399. @objc override open func isEqual(_ object: Any?) -> Bool {
  400. guard let ref = object as? StorageReference else {
  401. return false
  402. }
  403. return impl.isEqual(ref.impl)
  404. }
  405. @objc override public var hash: Int {
  406. return impl.hash
  407. }
  408. @objc override public var description: String {
  409. return impl.description
  410. }
  411. // MARK: - Internal APIs
  412. private let impl: FIRIMPLStorageReference
  413. internal convenience init(_ impl: FIRIMPLStorageReference) {
  414. self.init(impl: impl, storage: Storage(app: impl.storage.app, bucket: impl.bucket))
  415. }
  416. internal init(impl: FIRIMPLStorageReference, storage: Storage) {
  417. self.impl = impl
  418. self.storage = storage
  419. bucket = impl.bucket
  420. fullPath = impl.fullPath
  421. name = impl.name
  422. }
  423. }