storage fixes

This commit is contained in:
Arnaud Dorgans
2018-07-24 00:08:45 +02:00
parent 27605c6ff2
commit 8ca348fc0f
7 changed files with 391 additions and 6 deletions

View File

@@ -5,6 +5,7 @@ target 'RxFirebase_Example' do
pod 'RxFirebase/Firestore', :path => './'
pod 'RxFirebase/RemoteConfig', :path => './'
pod 'RxFirebase/Database', :path => './'
pod 'RxFirebase/Storage', :path => './'
target 'RxFirebase_Tests' do
inherit! :search_paths

View File

@@ -38,6 +38,9 @@ PODS:
- FirebaseInstanceID (~> 3.0)
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
- Protobuf (~> 3.5)
- FirebaseStorage (3.0.0):
- FirebaseCore (~> 5.0)
- GTMSessionFetcher/Core (~> 1.1)
- GoogleToolboxForMac/Defines (2.1.4)
- "GoogleToolboxForMac/NSData+zlib (2.1.4)":
- GoogleToolboxForMac/Defines (= 2.1.4)
@@ -60,6 +63,7 @@ PODS:
- gRPC/Main (1.11.0):
- gRPC-Core (= 1.11.0)
- gRPC-RxLibrary (= 1.11.0)
- GTMSessionFetcher/Core (1.1.15)
- leveldb-library (1.20)
- nanopb (0.3.8):
- nanopb/decode (= 0.3.8)
@@ -69,24 +73,29 @@ PODS:
- Protobuf (3.5.0)
- RxCocoa (4.1.2):
- RxSwift (~> 4.0)
- RxFirebase/Database (0.2):
- RxFirebase/Database (0.2.1):
- FirebaseDatabase (~> 5)
- RxCocoa (~> 4)
- RxSwift (~> 4)
- RxFirebase/Firestore (0.2):
- RxFirebase/Firestore (0.2.1):
- FirebaseFirestore (~> 0.12)
- RxCocoa (~> 4)
- RxSwift (~> 4)
- RxFirebase/RemoteConfig (0.2):
- RxFirebase/RemoteConfig (0.2.1):
- FirebaseRemoteConfig (~> 3)
- RxCocoa (~> 4)
- RxSwift (~> 4)
- RxFirebase/Storage (0.2.1):
- FirebaseStorage (~> 3)
- RxCocoa (~> 4)
- RxSwift (~> 4)
- RxSwift (4.1.2)
DEPENDENCIES:
- RxFirebase/Database (from `./`)
- RxFirebase/Firestore (from `./`)
- RxFirebase/RemoteConfig (from `./`)
- RxFirebase/Storage (from `./`)
SPEC REPOS:
https://github.com/cocoapods/specs.git:
@@ -98,11 +107,13 @@ SPEC REPOS:
- FirebaseFirestore
- FirebaseInstanceID
- FirebaseRemoteConfig
- FirebaseStorage
- GoogleToolboxForMac
- gRPC
- gRPC-Core
- gRPC-ProtoRPC
- gRPC-RxLibrary
- GTMSessionFetcher
- leveldb-library
- nanopb
- Protobuf
@@ -122,18 +133,20 @@ SPEC CHECKSUMS:
FirebaseFirestore: f686b8e83f3cf8bbc37db6e98e01029a14f01f55
FirebaseInstanceID: 83e0040351565df711a5db3d8ebe5ea21aca998a
FirebaseRemoteConfig: 3c57e4644bd6976b671ae0b725cd709f198bd1f5
FirebaseStorage: 7ca4bb7b58a25fa647b04f524033fc7cb7eb272b
GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f
gRPC: 70703dc9ba31c72341fc7f37745cc1c379edee96
gRPC-Core: 164639cd8ae18ca8b65477fafb2efbaecf4f181a
gRPC-ProtoRPC: bb5fddf3424aa4fad74d76736578a79fe40e244e
gRPC-RxLibrary: 26d53d1b1f306befd4ad4e15bd6de27839a82481
GTMSessionFetcher: 5fa5b80fd20e439ef5f545fb2cb3ca6c6714caa2
leveldb-library: 08cba283675b7ed2d99629a4bc5fd052cd2bb6a5
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03
RxCocoa: d88ba0f1f6abf040011a9eb4b539324fc426843a
RxFirebase: 564de37ff7429fb88313635d8a4b16c656bd9bbd
RxFirebase: 25a2fd31fe5795d90338fba7beb9b415209a215e
RxSwift: e49536837d9901277638493ea537394d4b55f570
PODFILE CHECKSUM: fde8e8f30c4a2721a77fa8212056b41e090fe118
PODFILE CHECKSUM: 973a2757330c974ebe33f0c1e979ded68c8ec05a
COCOAPODS: 1.5.2
COCOAPODS: 1.5.3

134
README.md
View File

@@ -20,6 +20,7 @@ it, simply add the following line to your Podfile:
pod 'RxFirebase/Firestore'
pod 'RxFirebase/RemoteConfig'
pod 'RxFirebase/Database'
pod 'RxFirebase/Storage'
```
## Usage
@@ -31,6 +32,7 @@ import RxFirebase
- [Database](#database)
- [Firestore](#firestore)
- [RemoteConfig](#remoteconfig)
- [Storage](#storage)
### Database
@@ -300,6 +302,138 @@ RemoteConfig.remoteConfig()
// https://firebase.google.com/docs/remote-config/ios
```
### Storage
Upload:
```swift
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
.rx
let data: Data // Upload data
reference.putData(data)
.subscribe(onNext: { metadata in
// Success
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
let fileURL: URL // Upload file
reference.putFile(from: fileURL)
.subscribe(onNext: { metadata in
// Success
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
```
Observe events:
```swift
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
.rx
let fileURL: URL // Upload file
let uploadTask = reference.putFile(from: fileURL)
// Listen for state changes
task.rx.observe(.progress)
.subscribe(onNext: { snapshot in
// Upload reported progress
let percentComplete = 100.0 * Double(snapshot.progress!.completedUnitCount)
/ Double(snapshot.progress!.totalUnitCount)
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
```
Download:
```swift
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
.rx
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
reference.getData(maxSize: 1 * 1024 * 1024)
.subscribe(onNext: { data in
// Data for "images/space.jpg" is returned
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
// Create local filesystem URL
let localURL = URL(string: "path/to/image")!
// Download to the local filesystem
reference.write(toFile: localURL)
.subscribe(onNext: { data in
// Local file URL for "images/space.jpg" is returned
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
```
URL:
```swift
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
.rx
// Fetch the download URL
reference.downloadURL()
.subscribe(onNext: { url in
// Get the download URL for 'images/space.jpg'
}, onError: { error in
// Handle any errors
}).disposed(by: disposeBag)
```
Metadata:
```swift
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
.rx
// Create file metadata to update
let newMetadata = StorageMetadata()
// Update metadata properties
reference.updateMetadata(newMetadata)
.subscribe(onNext: { metadata in
// Updated metadata for 'images/space.jpg' is returned
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
// Get metadata properties
reference.getMetadata()
.subscribe(onNext: { metadata in
// Metadata now contains the metadata for 'images/space.jpg'
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
```
Delete:
```swift
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
.rx
// Delete the file
reference.delete()
.subscribe(onNext: {
// File deleted successfully
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
```
## License
This library belongs to _RxSwiftCommunity_.

View File

@@ -48,4 +48,8 @@ Pod::Spec.new do |s|
database.source_files = 'Sources/Database/**/*'
database.dependency 'FirebaseDatabase', '~> 5'
end
s.subspec 'Storage' do |storage|
storage.source_files = 'Sources/Storage/**/*'
storage.dependency 'FirebaseStorage', '~> 3'
end
end

View File

@@ -305,6 +305,7 @@
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-RxFirebase_Example/Pods-RxFirebase_Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/BoringSSL/openssl.framework",
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
"${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework",
"${BUILT_PRODUCTS_DIR}/Protobuf/Protobuf.framework",
"${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework",
@@ -319,6 +320,7 @@
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Protobuf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework",

View File

@@ -0,0 +1,30 @@
//
// FIRStorageObservableTask+Rx.swift
// RxFirebase
//
// Created by Arnaud Dorgans on 19/07/2018.
//
import UIKit
import RxSwift
import FirebaseStorage
extension Reactive where Base: StorageObservableTask {
/**
* Observes changes in the upload status: Resume, Pause, Progress, Success, and Failure.
* @param status The FIRStorageTaskStatus change to observe.
* @param handler A callback that fires every time the status event occurs,
* returns a FIRStorageTaskSnapshot containing the state of the task.
*/
public func observe(_ status: StorageTaskStatus) -> Observable<StorageTaskSnapshot> {
return Observable.create { observer in
let handle = self.base.observe(status) { snapshot in
observer.onNext(snapshot)
}
return Disposables.create {
self.base.removeObserver(withHandle: handle)
}
}
}
}

View File

@@ -0,0 +1,201 @@
//
// FIRStorageReference+Rx.swift
// RxFirebase
//
// Created by Arnaud Dorgans on 19/07/2018.
//
import RxSwift
import FirebaseStorage
extension Reactive where Base: StorageReference {
/**
* Asynchronously uploads data to the currently specified FIRStorageReference.
* This is not recommended for large files, and one should instead upload a file from disk.
* @param uploadData The NSData to upload.
* @param metadata FIRStorageMetadata containing additional information (MIME type, etc.)
* about the object being uploaded.
* @param completion A completion block that either returns the object metadata on success,
* or an error on failure.
*/
public func putData(_ uploadData: Data, metadata: StorageMetadata? = nil) -> Observable<StorageMetadata> {
return Observable.create { observer in
let task = self.base.putData(uploadData, metadata: metadata) { metadata, error in
guard let error = error else {
if let metadata = metadata {
observer.onNext(metadata)
}
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create {
task.cancel()
}
}
}
/**
* Asynchronously uploads a file to the currently specified FIRStorageReference.
* @param fileURL A URL representing the system file path of the object to be uploaded.
* @param metadata FIRStorageMetadata containing additional information (MIME type, etc.)
* about the object being uploaded.
* @param completion A completion block that either returns the object metadata on success,
* or an error on failure.
*/
public func putFile(from url: URL, metadata: StorageMetadata? = nil) -> Observable<StorageMetadata> {
return Observable.create { observer in
let task = self.base.putFile(from: url, metadata: metadata) { metadata, error in
guard let error = error else {
if let metadata = metadata {
observer.onNext(metadata)
}
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create {
task.cancel()
}
}
}
/**
* Asynchronously downloads the object at the FIRStorageReference to an NSData object in memory.
* An NSData of the provided max size will be allocated, so ensure that the device has enough free
* memory to complete the download. For downloading large files, writeToFile may be a better option.
* @param size The maximum size in bytes to download. If the download exceeds this size
* the task will be cancelled and an error will be returned.
* @param completion A completion block that either returns the object data on success,
* or an error on failure.
*/
public func getData(maxSize: Int64) -> Observable<Data> {
return Observable.create { observer in
let task = self.base.getData(maxSize: maxSize) { data, error in
guard let error = error else {
if let data = data {
observer.onNext(data)
}
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create {
task.cancel()
}
}
}
/**
* Asynchronously retrieves a long lived download URL with a revokable token.
* This can be used to share the file with others, but can be revoked by a developer
* in the Firebase Console if desired.
* @param completion A completion block that either returns the URL on success,
* or an error on failure.
*/
public func downloadURL() -> Observable<URL> {
return Observable.create { observer in
self.base.downloadURL { url, error in
guard let error = error else {
if let url = url {
observer.onNext(url)
}
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create()
}
}
/**
* Asynchronously downloads the object at the current path to a specified system filepath.
* @param fileURL A file system URL representing the path the object should be downloaded to.
* @param completion A completion block that fires when the file download completes.
* Returns an NSURL pointing to the file path of the downloaded file on success,
* or an error on failure.
*/
public func write(toFile url: URL) -> Observable<URL> {
return Observable.create { observer in
let task = self.base.write(toFile: url) { url, error in
guard let error = error else {
if let url = url {
observer.onNext(url)
}
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create {
task.cancel()
}
}
}
/**
* Retrieves metadata associated with an object at the current path.
* @param completion A completion block which returns the object metadata on success,
* or an error on failure.
*/
public func getMetadata() -> Observable<StorageMetadata> {
return Observable.create { observer in
self.base.getMetadata { metadata, error in
guard let error = error else {
if let metadata = metadata {
observer.onNext(metadata)
}
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create()
}
}
/**
* Updates the metadata associated with an object at the current path.
* @param metadata An FIRStorageMetadata object with the metadata to update.
* @param completion A completion block which returns the FIRStorageMetadata on success,
* or an error on failure.
*/
public func updateMetadata(_ metadata: StorageMetadata) -> Observable<StorageMetadata> {
return Observable.create { observer in
self.base.updateMetadata(metadata) { metadata, error in
guard let error = error else {
if let metadata = metadata {
observer.onNext(metadata)
}
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create()
}
}
/**
* Deletes the object at the current path.
* @param completion A completion block which returns nil on success, or an error on failure.
*/
public func delete() -> Observable<Void> {
return Observable.create { observer in
self.base.delete { error in
guard let error = error else {
observer.onNext(())
observer.onCompleted()
return
}
observer.onError(error)
}
return Disposables.create()
}
}
}