π Third-party authentication done in a single line of code
βοΈ Send and receive Firestore documents in a snap
π Predefined user protocols with built-in features
π₯ Firebase solutions in one native Swift package
π Fully documented code with examples
π Ready to get started? Check out our complete wiki for detailed guides.
GitHub release (latest SemVer) GitHub Release Date GitHub issues GitHub pull requests
EasyFirebase is a Swift wrapper for all things Firebase. Save hours from implementing the Firebase code in your projects repeatedly. EasyFirebase makes document storage and retrieval easier by providing intuitive protocols for Firestore. EasyFirebase makes authentication easier with the EasyUser (subclassable) open class and simple one-line sign-in with Google and Apple. EasyFirebase is cross-platform and works with both iOS and macOS.
- Firestore Support
- Authentication Support
- Storage Support
- Data storage β
- Safe data overriding
- Data removal
- Data upload task visibility
- Cloud Messaging Support
- Built-in user notifications β
- Built-in MessagingNotification protocol
- Built-in 3P notifications
- User notification settings
- Analytics Support
All the above features are cross-platform and are supported on both iOS and macOS.
βοΈ This means EasyFirebase is the quickest way to implement Sign In with Google on macOS! βοΈ
Add EasyFirebase to your project using Swift Package Manager:
https://github.com/Flowductive/easy-firebase
Import EasyFirebase:
import EasyFirebaseConfigure at app launch:
// You don't need to call FirebaseApp.configure() when this is called! EasyFirebase.configure()
Save time writing model classes with the built-in Document protocol:
class Car: Document { // These properties are inherited from Document var id: String = UUID().uuidString var dateCreated: Date = Date() // Define your own custom properties var make: String var model: String var year: Int init(make: String, model: String, year: Int) { // ... } }
Store documents anywhere in your code:
var myCar = Car(make: "Toyota", model: "Corolla", year: 2017) // Store the car instance in the 'car' collection in Firestore myCar.set() // Static method that does the same as above EasyFirestore.Storage.set(myCar)
Grab documents easily without needing to specify a collection name:
EasyFirestore.Retrieval.get(id: myCarID, ofType: Car.self) { car in guard let car = car else { return } self.myOtherCar = car }
Update fields remotely in Firestore without performing any reads.
// Append element to array EasyFirestore.Updating.append(\.ingredients, with: "Cheese", in: pizzaDocument) { error in ... } // Increment field EasyFirestore.Updating.increment(\.pepperoniCount, by: 5, in: pizzaDocument) // Remove elements from array EasyFirestore.Updating.remove(\.ingredients, taking: ["Garlic", "Anchovies", "Pineapple"], from: pizzaDocument)
Grab documents and update the local instance when changed in Firestore:
EasyFirestore.Listening.listen(to: otherCarID, ofType: Car.self, key: "myCarListenerKey") { car in // Updates when changed in Firestore guard let car = car else { return } self.myOtherCar = car }
EasyFirestore will automatically cache fetched documents locally and will use the cached doucments when retrieving to reduce your Firestore read count.
// EasyFirebase will automatically cache fetched objects for you, here is a manual example EasyFirestore.Cacheing.register(myCar) // Get locally cached objects instantly. Retrieving objects using EasyFirestore.Retrieval will grab cached objects if they exist var cachedCar = EasyFirestore.Cacheing.grab(myCarID, fromType: Car.self)
Link child documents to an array of IDs in a parent document:
var car1 = Car(make: "Toyota", model: "Corolla", year: 2017) var car2 = Car(make: "Honda", model: "Civic", year: 2019) var dealership = Dealership(name: "Los Angeles Dealership") // Set and assign the Toyota Corolla to the Los Angeles Dealership car1.setAssign(toField: "cars", using: \.cars, in: dealership) // Set and assign the Honda Civic to the Los Angeles Dealership car2.set() car2.assign(toField: "cars", using: \.cars, in: dealership)
Easily query for documents:
EasyFirestore.Querying.where(\Car.make, .equals, "Toyota") { cars in // Handle your queried documents here... }
Use multiple conditions for queries; order and limit results:
EasyFirestore.Querying.where((\Car.year, .greaterEqualTo, 2010), (\Car.model, .in, ["Corolla", "Camry"]), order: .ascending, limit: 5 ) { cars in // ... }
Save time writing user classes with the built-in EasyUser open class:
class MyUser: EasyUser { // EasyUser comes pre-built with these automatically updated properties var lastSignon: Date var displayName: String var username: String var email: String var appVersion: String var deviceToken: String? var notifications: [MessagingNotification] var disabledMessageCategories: [MessageCategory] var progress: Int var id: String var dateCreated: Date // Define your own custom properties var cars: [Car.ID] // ... }
Authenticate with an email and password easily:
EasyAuth.createAccount(email: "easy.firebase@example.com", password: "76dp2[&y4;JLyu:F") { error in if let error = error { print(error.localizedDescription) } else { // Account created! } } EasyAuth.signIn(email: "easy.firebase@example.com", password: "76dp2[&y4;JLyu:F") { error in // ... }
Authenticate with Google:
// iOS EasyAuth.signInWithGoogle(clientID: "xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") { error in // ... } // macOS EasyAuth.signInWithGoogle(clientID: "xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", secret: "GOCSPX-xxxxxxxxxxxxxxxxxxx-xxxxxxxx") { error in // ... }
Authenticate with Apple:
// iOS + macOS EasyAuth.signInWithApple()
Generate unique usernames and update easily:
user.safelyUpdateUsername(to: "myNewUsername", ofUserType: MyUser.self) { error, suggestion in if let error = error { // ... } else if let suggestion = suggestion { // Username taken, provide the user with an available username suggestion. } else { // Success! Username changed. } }
Quickly update and manage EasyAuth users:
// Send a verfication email to the currently signed-in user user.sendEmailVerification(completion: { error in }) // Upload and update the current user's profile photo user.updatePhoto(with: myPhotoData, ofUserType: FUser.self, completion: { error in }) // Send the current user's password reset form to a specified email user.sendPasswordReset(toEmail: "myResetEmail@example.com", completion: { error in }) // Update the current user's display name user.updateDisplayName(to: "New_DisplayName", ofUserType: MyUser.self, completion: { error in }) // Update the current user's password user.updatePassword(to: "newPassword", completion: { error in }) // Delete the current user user.delete(ofUserType: MyUser.self, completion: { error in })
Quickly assign data to Firebase Storage using a single line of code.
// Upload image data and get an associated URL EasyStorage.put(imageData, to: StorageResource(id: user.id)) { url in } // EasyStorage will automatically delete existing images matching the same ID (if in the same folder) EasyStorage.put(imageData,to: StorageResource(id: user.id, folder: "myFolder"), progress: { updatedProgress in // Update progress text label using updatedProgress }, completion: { url in // Handle the image's URL })
Easily send and notify other users without all the tedious setup. Just add a serverKey from Firebase Console.
// Set your Server Key EasyMessaging.serverKey = "xxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxx-xxxxx-xxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxx" // Create the notification let notification = MessagingNotification("Message body", from: me, in: "Test Category") // Send the notification to the user // Appends to the notifications property, unless the specified category is in the user's disabledMessageCategories EasyMessaging.send(notification, to: you)
To log an event, you can use EasyAnalytics' static methods:
EasyAnalytics.log("food_eaten", data: [ "name": "Hot Dog", "isHot": true ])
If you have a model that conforms to AnalyticsLoggable, you can log events using the model itself:
let hotdog = Food(name: "Hot Dog", temperature: 81) EasyAnalytics.log("food_eaten", model: hotdog)
Alternatively, you can call the logging method from the model itself:
hotdog.log(key: "food_eaten")
Override the analyticsProperties() method to automatically update user properties on app launch:
struct MyUser: EasyUser { // ... var favoriteCar: String func analyticsProperties() -> [String: String] { return ["app_version": appVersion, "favorite_car": favoriteCar] } }
Manually update the user properties to Firebase Analytics:
myUser.updateAnalyticsUserProperties()