mirror of
https://github.com/caoer/RxFirebase.git
synced 2026-01-12 22:52:01 +08:00
storage fixes
This commit is contained in:
1
Podfile
1
Podfile
@@ -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
|
||||
|
||||
25
Podfile.lock
25
Podfile.lock
@@ -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
134
README.md
@@ -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_.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
30
Sources/Storage/FIRStorageObservableTask+Rx.swift
Normal file
30
Sources/Storage/FIRStorageObservableTask+Rx.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
201
Sources/Storage/FIRStorageReference+Rx.swift
Normal file
201
Sources/Storage/FIRStorageReference+Rx.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user