RxFirebase
Requirements
Xcode 9.0
Swift 4.0
Installation
RxFirebase is available through CocoaPods. To install it, simply add the following lines to your Podfile:
iOS
pod 'RxFirebase/Firestore'
pod 'RxFirebase/RemoteConfig'
pod 'RxFirebase/Database'
pod 'RxFirebase/Storage'
pod 'RxFirebase/Auth'
pod 'RxFirebase/Functions'
tvOS/macOS
pod 'RxFirebaseAuthentication'
pod 'RxFirebaseStorage'
pod 'RxFirebaseDatabase'
Usage
import RxFirebase
Database
Basic write operation:
let ref = Database.database().reference()
ref.child("users")
.child("1")
.rx
.setValue(["username": "Arnonymous"])
.subscribe(onNext: { _ in
print("Document successfully updated")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/database/ios/read-and-write#basic_write
Listen for value events:
let ref = Database.database().reference()
ref.child("users")
.child("1")
.rx
.observeEvent(.value)
.subscribe(onNext: { snapshot in
print("Value:\(snapshot.value)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/database/ios/read-and-write#listen_for_value_events
Read data once:
let ref = Database.database().reference()
ref.child("users")
.child("1")
.rx
.observeSingleEvent(.value)
.subscribe(onNext: { snapshot in
print("Value:\(snapshot.value)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/database/ios/read-and-write#read_data_once
Update specific fields:
let ref = Database.database().reference()
let childUpdates = ["/posts/\(key)": post,
"/user-posts/\(userID)/\(key)/": post]
ref.rx.updateChildValues(childUpdates)
.subscribe(onNext: { _ in
// Success
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/database/ios/read-and-write#update_specific_fields
Delete data:
let ref = Database.database().reference()
ref.rx.removeValue()
.subscribe(onNext: { _ in
// Success
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/database/ios/read-and-write#delete_data
Save data as transactions
let ref = Database.database().reference()
ref.rx.runTransactionBlock { currentData in
// TransactionResult
}.subscribe(onNext: { _ in
// Success
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/database/ios/read-and-write#save_data_as_transactions
Firestore
Setting data:
let db = Firestore.firestore()
// Add a new document in collection "cities"
db.collection("cities")
.document("SF")
.rx
.setData([
"name": "San Francisco",
"state": "CA",
"country": "USA",
"capital": false,
"population": 860000
]).subscribe(onError: { error in
print("Error setting data: \(error)")
}).disposed(by: disposeBag)
// Add a new document with a generated id.
db.collection("cities")
.rx
.addDocument(data: [
"name": "San Francisco",
"state": "CA",
"country": "USA",
"capital": false,
"population": 860000
]).subscribe(onNext: { ref in
print("Document added with ID: \(ref.documentID)")
}, onError: { error in
print("Error adding document: \(error)")
}).disposed(by: disposeBag)
// Set the "capital" field of the city 'SF'
db.collection("cities")
.document("SF")
.rx
.updateData([
"capital": true
]).subscribe(onNext: {
print("Document successfully updated")
}, onError: { error in
print("Error updating document: \(error)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/firestore/manage-data/add-data
Get a document:
let db = Firestore.firestore()
db.collection("cities")
.document("SF")
.rx
.getDocument()
.subscribe(onNext: { document in
if let document = document {
print("Document data: \(document.data())")
} else {
print("Document does not exist")
}
}, onError: { error in
print("Error fetching snapshots: \(error)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/firestore/query-data/get-data
Get Realtime Updates:
let db = Firestore.firestore()
// Document
db.collection("cities")
.document("SF")
.rx
.listen()
.subscribe(onNext: { document in
print("Current data: \(document.data())")
}, onError: { error in
print("Error fetching snapshots: \(error)")
}).disposed(by: disposeBag)
// Collection
db.collection("cities")
.rx
.listen()
.subscribe(onNext: { snapshot in
snapshot.documentChanges.forEach { diff in
if (diff.type == .added) {
print("New city: \(diff.document.data())")
}
if (diff.type == .modified) {
print("Modified city: \(diff.document.data())")
}
if (diff.type == .removed) {
print("Removed city: \(diff.document.data())")
}
}
}, onError: { error in
print("Error fetching snapshots: \(error)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/firestore/query-data/listen
Batched writes:
let db = Firestore.firestore()
// Get new write batch
let batch = db.batch()
// Update the population of 'SF'
let sfRef = db.collection("cities").document("SF")
batch.updateData(["population": 1000000 ], forDocument: sfRef)
// Commit the batch
batch.rx
.commit()
.subscribe(onNext: {
print("Batch write succeeded.")
}, onError: { error in
print("Error writing batch \(error)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/firestore/manage-data/transactions
Transactions:
let db = Firestore.firestore()
let sfReference = db.collection("cities").document("SF")
db.rx.runTransaction { transaction in
let sfDocument = try transaction.getDocument(sfReference)
guard let oldPopulation = sfDocument.data()?["population"] as? Int else {
let error = NSError(
domain: "AppErrorDomain",
code: -1,
userInfo: [
NSLocalizedDescriptionKey: "Unable to retrieve population from snapshot \(sfDocument)"
]
)
throw error
}
transaction.updateData(["population": oldPopulation + 1], forDocument: sfReference)
return nil
}.subscribe(onNext: { _ in
print("Transaction successfully committed!")
}, onError: { error in
print("Transaction failed: \(error)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/firestore/manage-data/transactions
RemoteConfig
Fetch:
// TimeInterval is set to expirationDuration here, indicating the next fetch request will use
// data fetched from the Remote Config service, rather than cached parameter values, if cached
// parameter values are more than expirationDuration seconds old. See Best Practices in the
// README for more information.
RemoteConfig.remoteConfig()
.rx
.fetch(withExpirationDuration: TimeInterval(expirationDuration), activateFetched: true)
.subscribe(onNext: { status in
print("Config fetched! with success:\(status == .success)")
}, onError: { error in
print("Error: \(error)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/remote-config/ios
Storage
Upload:
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:
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
uploadTask.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:
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:
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:
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:
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)
Auth
Create:
let auth = Auth.auth()
// Create a password-based account
auth.rx.createUser(withEmail: "[email protected]", password: "1q2w3e4r")
.subscribe(onNext: { authResult in
// User signed in
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/auth/ios/password-auth
Sign In:
let auth = Auth.auth()
// Sign in a user with an email address and password
auth.rx.signIn(withEmail: "[email protected]", password: "1q2w3e4r")
.subscribe(onNext: { authResult in
// User signed in
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/auth/ios/password-auth
User
Update Email:
let user = Auth.auth().currentUser?
// Set a user's email address
user.rx.updateEmail(to: "[email protected]")
.subscribe(onNext: {
// Completed updating Email
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/auth/ios/manage-users
Delete:
let user = Auth.auth().currentUser?
// Delete a user
user.rx.delete()
.subscribe(onNext: {
// User deleted
}, onError: { error in
// Uh-oh, an error occurred!
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/auth/ios/manage-users
Functions
let functions = Functions.functions()
let request = functions.httpsCallable("functionName").rx
request
.call(["parameter": "value"])
.subscribe(onNext: { result in
print("response:\(result)")
}, onError: { error in
print("error:\(error)")
}).disposed(by: disposeBag)
// https://firebase.google.com/docs/functions/callable#call_the_function
License
This library belongs to RxSwiftCommunity.
RxFirebase is available under the MIT license. See the LICENSE file for more info.