Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/urban-health-labs/CombineFirebase
Combine wrapper on Google's iOS Firebase library.
https://github.com/urban-health-labs/CombineFirebase
apple combine combine-framework database firebase firebase-db firebase-firestore firebase-functions firebase-realtime-database firebase-storage firestore google ios ios13 publisher remoteconfig storage swift swift5-1 swiftui
Last synced: 3 months ago
JSON representation
Combine wrapper on Google's iOS Firebase library.
- Host: GitHub
- URL: https://github.com/urban-health-labs/CombineFirebase
- Owner: urban-health-labs
- License: mit
- Created: 2020-02-21T16:50:55.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-02-07T08:12:54.000Z (almost 2 years ago)
- Last Synced: 2024-04-04T17:34:23.119Z (7 months ago)
- Topics: apple, combine, combine-framework, database, firebase, firebase-db, firebase-firestore, firebase-functions, firebase-realtime-database, firebase-storage, firestore, google, ios, ios13, publisher, remoteconfig, storage, swift, swift5-1, swiftui
- Language: Swift
- Homepage:
- Size: 27.6 MB
- Stars: 222
- Watchers: 9
- Forks: 45
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# CombineFirebase
[![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-informational)](#swift-package-manager)
[![Version](https://img.shields.io/cocoapods/v/CombineFirebase.svg?style=flat)](https://cocoapods.org/pods/CombineFirebase)
[![License](https://img.shields.io/cocoapods/l/CombineFirebase.svg?style=flat)](https://cocoapods.org/pods/CombineFirebase)
[![Platform](https://img.shields.io/cocoapods/p/CombineFirebase.svg?style=flat)](https://cocoapods.org/pods/CombineFirebase)Handling [Firebase](https://github.com/firebase/firebase-ios-sdk) asynchronous callbacks with [Combine](https://developer.apple.com/documentation/combine) framework.
## Example
To run the example project, clone the repo, and run `pod install` from the Example directory first. See [Usage](#Usage) below for more information.
## Requirements
* Xcode 11.3+ | Swift 5.1+
* iOS 13.0+ | tvOS 13.0+ | macOS 10.15+## Installation
#### CocoaPods
`CombineFirebase` is available through [CocoaPods](https://cocoapods.org). To install it, simply add the following line to your Podfile:
``` ruby
pod 'CombineFirebase/Firestore'
pod 'CombineFirebase/RemoteConfig'
pod 'CombineFirebase/Database'
pod 'CombineFirebase/Storage'
pod 'CombineFirebase/Auth'
pod 'CombineFirebase/Functions'
```#### Swift Package Manager
`CombineFirebase` is available through [Swift Package Manager](https://swift.org/package-manager/) in beta status. To install it, you must have **Xcode 12.0** and above, simply add `CombineFirebase` to an existing Xcode project as a package dependency:
1. From the **File** menu, select **Swift Packages > Add Package Dependency...**
2. Enter https://github.com/rever-ai/CombineFirebase into the package repository URL text field.
3. Xcode should choose updates package up to the next version option by default.## Usage
``` swift
import CombineFirebase
import Firebase
import Combine
```* [Database](#database)
* [Firestore](#firestore)
* [RemoteConfig](#remoteconfig)
* [Storage](#storage)
* [Auth](#auth)
* [Functions](#functions)### Database
Basic write operation
``` swift
var cancelBag = Set()func setUserData() {
let ref = Database.database().reference()ref.child("users")
.child("1")
.setValue(["username": "Arnonymous"])
.sink { _ in
print("Document successfully updated")
}.store(in: &cancelBag)
}// https://firebase.google.com/docs/database/ios/read-and-write#basic_write
```Listen for value events
``` swift
var cancelBag = Set()func listenForValueEvent() {
let ref = Database.database().reference()ref.child("users")
.child("1")
.publisher(.value)
.receive(on: RunLoop.main)
.sink { snapshot in
print("Value:\(snapshot.value)")
}.store(in: &cancelBag)
}
// https://firebase.google.com/docs/database/ios/read-and-write#listen_for_value_events
```Read data once
``` swift
var cancelBag = Set()func readDataOnce() {
let ref = Database.database().reference()ref.child("users")
.child("1")
.observeSingleEvent(.value)
.receive(on: RunLoop.main)
.sink { snapshot in
print("Value:\(snapshot.value)")
}.store(in: &cancelBag)
}
// https://firebase.google.com/docs/database/ios/read-and-write#read_data_once
```Update specific fields
``` swift
var cancelBag = Set()func updateFields() {
let ref = Database.database().reference()let childUpdates = ["/posts/\(key)": post,
"/user-posts/\(userID)/\(key)/": post]
ref.updateChildValues(childUpdates)
.receive(on: RunLoop.main)
.sink { _ in
// Success
}.store(in: &cancelBag)
}// https://firebase.google.com/docs/database/ios/read-and-write#update_specific_fields
```Delete data
``` swift
var cancelBag = Set()func deleteData() {
let ref = Database.database().reference()ref.removeValue()
.receive(on: RunLoop.main)
.sink { _ in
// Success
}.store(in: &cancelBag)
}
// https://firebase.google.com/docs/database/ios/read-and-write#delete_data
```Save data as transactions
``` swift
var cancelBag = Set()func saveDataAsTransaction() {
let ref = Database.database().reference()ref.runTransactionBlock { currentData in
// TransactionResult
}.sink { _ in
// Success
}.store(in: &cancelBag)
}
// https://firebase.google.com/docs/database/ios/read-and-write#save_data_as_transactions
```### Firestore
Setting data
``` swift
var cancelBag = Set()let db = Firestore.firestore()
struct City: Codable {
var name: String? = nil
var state: String? = nil
var country: String? = nil
var capital: String? = nil
var population: Int? = nil
// local variable
var id: String? = nil
}func setSanFranciscoData(city: City) {
let onErrorCompletion: ((Subscribers.Completion) -> Void)? = { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}let onValue: (Void) -> Void = {
print("✅ value")
}// Add a new document in collection "cities"
(db.collection("cities")
.document("SF")
.setData(from: city) as AnyPublisher) // Note: you can use (as Void) for simple setData({})
.sink(receiveCompletion: onErrorCompletion, receiveValue: onValue)
.store(in: &cancelBag)
}
// Add a new document with a generated id.
func addSanFranciscoDocument(city: City) {
(db.collection("cities")
.addDocument(data: [
"name": "San Francisco",
"state": "CA",
"country": "USA",
"capital": false,
"population": 860000
]) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}) { ref in
print("Document added with ID: \(ref.documentID)")
}
.store(in: &cancelBag)
}
// Set the "capital" field of the city 'SF'
func updateSanFranciscoDocument() {
(db.collection("cities")
.document("SF")
.updateData([
"capital": true
]) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print(i"❗️ failure: \(error)")
}) { _ in }
.store(in: &cancelBag)
}
// https://firebase.google.com/docs/firestore/manage-data/add-data
```Get a document
``` swift
func getDocument() {
db.collection("cities")
.document("SF")
.getDocument()
.sink(receiveCompletion: { (completion) in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { document in
print("Document data: \(document.data())")
}
.store(in: &cancelBag)
}func getDocumentAsObject() {
db.collection("cities")
.document("SF")
.getDocument(as: City.self)
.sink(receiveCompletion: { (completion) in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { city in
print("City: \(city)")
}
.store(in: &cancelBag)
}
// https://firebase.google.com/docs/firestore/query-data/get-data
```Get Realtime updates
``` swift
let db = Firestore.firestore()// Document
func listenDocument() {
db.collection("cities")
.document("SF")
.publisher()
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { document in
print("Document data: \(document.data())")
}
.store(in: &cancelBag)
}var cityDocumentSnapshotMapper: (DocumentSnapshot) throws -> City? {
{
var city = try $0.data(as: City.self)
city.id = $0.documentID
return city
}
}func listenDocumentAsObject() {
db.collection("cities")
.document("SF")
.publisher(as: City.self, documentSnapshotMapper: cityDocumentSnapshotMapper)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { city in
print("City: \(city)")
}
.store(in: &cancelBag)
}
// Collection
func listenCollection() {
db.collection("cities")
.publisher()
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { snapshot in
print("collection data: \(snapshot.documents)")
}.store(in: &cancelBag)
}func listenCollectionAsObject() {
db.collection("cities")
.publisher(as: City.self, documentSnapshotMapper: cityDocumentSnapshotMapper)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { cities in
print("Cities: \(cities)")
}.store(in: &cancelBag)
}// https://firebase.google.com/docs/firestore/query-data/listen
```Batched writes
``` swift
var cancelBag = Set()func batchWrite() {
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.commit()
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { _ in}
.store(in: &cancelBag)
}
// https://firebase.google.com/docs/firestore/manage-data/transactions
```Transactions
``` swift
var cancelBag = Set()func transaction() {
let db = Firestore.firestore()
let sfReference = db.collection("cities").document("SF")(db.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
} as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { _ in
print("Transaction successfully committed!")
}
.store(in: &cancelBag)
}
// https://firebase.google.com/docs/firestore/manage-data/transactions
```### RemoteConfig
Fetch
``` swift
// 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.var cancelBag = Set()
func fetchRemoteConfig() {
(RemoteConfig.remoteConfig()
.fetch(withExpirationDuration: TimeInterval(expirationDuration), activateFetched: true) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("❗️ failure: \(error)")
}
}) { status in
print("Config fetched! with success:\(status == .success)")
}
.store(in: &cancelBag)
}// https://firebase.google.com/docs/remote-config/ios
```### Storage
Upload
``` swift
var cancelBag = Set()let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
let data: Data // Upload data
(reference.putData(data) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { metadata in
// Success
}
.store(in: &cancelBag)
let fileURL: URL // Upload file
(reference.putFile(from: fileURL) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { metadata in
// Success
}
.store(in: &cancelBag)
```Observe events
``` swift
var cancelBag = Set()
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")let fileURL: URL // Upload file
let uploadTask = reference.putFile(from: fileURL)// Listen for state changes
uploadTask.publisher(.progress)
.sink(receiveCompletion: { _ in
print("🏁 finished")
}) { snapshot in
if let error = snapshot.error {
print("error: \(error)")
}
// Upload reported progress
let percentComplete = 100.0 * Double(snapshot.progress?.completedUnitCount ?? 0)
/ Double(snapshot.progress.totalUnitCount ?? 1)
}
.store(in: &cancelBag)
```Download
``` swift
var cancelBag = Set()
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
(reference.getData(maxSize: 1 * 1024 * 1024) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { data in
// Data for "images/space.jpg" is returned
}
.store(in: &cancelBag)
// Create local filesystem URL
let localURL = URL(string: "path/to/image")!
// Download to the local filesystem
(reference.write(toFile: localURL) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { data in
// Local file URL for "images/space.jpg" is returned
}
.store(in: &cancelBag)
```URL
``` swift
var cancelBag = Set()
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
// Fetch the download URL
(reference.downloadURL() as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { data in
// Get the download URL for 'images/space.jpg'
}
.store(in: &cancelBag)
```Metadata
``` swift
var cancelBag = Set()
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
// Create file metadata to update
let newMetadata = StorageMetadata()
// Update metadata properties
(reference.updateMetadata(newMetadata) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { metadata in
// Updated metadata for 'images/space.jpg' is returned
}
.store(in: &cancelBag)
// Get metadata properties
(reference.getMetadata() as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { metadata in
// Metadata now contains the metadata for 'images/space.jpg'
}
.store(in: &cancelBag)
```Delete
``` swift
var cancelBag = Set()
let reference = Storage.storage()
.reference(forURL: "\(your_firebase_storage_bucket)/images/space.jpg")
// Delete the file
(reference.delete() as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { _ in
// File deleted successfully
}
.store(in: &cancelBag)
```### Auth
Create
``` swift
var cancelBag = Set()
let auth = Auth.auth()
// Create a password-based account
(auth.createUser(withEmail: "[email protected]", password: "1q2w3e4r") as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { _ in
// User signed in
}.store(in: &cancelBag)// https://firebase.google.com/docs/auth/ios/password-auth
```Sign in
``` swift
var cancelBag = Set()let auth = Auth.auth()
// Sign in a user with an email address and password
(auth.signIn(withEmail: "[email protected]", password: "1q2w3e4r") as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { _ in
// User signed in
}.store(in: &cancelBag)// https://firebase.google.com/docs/auth/ios/password-auth
```#### User
Update email
``` swift
var cancelBag = Set()
let user = Auth.auth().currentUser
// Set a user's email address
(user.updateEmail(to: "[email protected]") as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { _ in
// Completed updating Email
}.store(in: &cancelBag)// https://firebase.google.com/docs/auth/ios/manage-users
```Delete
``` swift
var cancelBag = Set()
let user = Auth.auth().currentUser// Delete a user
(user.delete() as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): // Uh-oh, an error occurred!
}
}) { _ in
// User deleted
}.store(in: &cancelBag)// https://firebase.google.com/docs/auth/ios/manage-users
```### Functions
``` swift
var cancelBag = Set()
let functions = Functions.functions()
let request = functions.httpsCallable("functionName")(request
.call(["parameter": "value"]) as AnyPublisher)
.sink(receiveCompletion: { completion in
switch completion {
case .finished: print("🏁 finished")
case .failure(let error): print("error:\(error)")
}
}) { result in
print("response:\(result)")
}.store(in: &cancelBag)
// https://firebase.google.com/docs/functions/callable#call_the_function
```## Author
Kumar Shivang, [email protected]
## License
CombineFirebase is available under the MIT license. See the [LICENSE](LICENSE) file for more info.