Ilya Loshkarev loshkarev.i@gmail.com
SFEDU 2017
An API provider that covers most of the mobile application server tasks
Pros:
Cons:
CloudKit | Firebase | AWS | |
---|---|---|---|
Supplier | Apple | Amazon | |
Platforms | iOS, JS, Web | iOS, Android, JS, Web, C++, Unity | iOS, Android, JS, Web, C++, Unity |
Complexity | Low | Average | High |
Open Source | - | +/- | - |
Prices are usually scaled on data per user basis.
Requires Apple Developer account to use
GoogleService-Info.plist
from online project configuratorGoogleService-Info.plist
to your XCode projectPodfile
use_frameworks!
source 'https://github.com/CocoaPods/Specs.git'
target 'firebase-test' do
pod 'Firebase/Core'
pod 'Firebase/Auth'
pod 'Firebase/Database'
# ...
end
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
}
Firebase supports several providers of user credentials:
Also a backend service,
easy-to-use SDKs,
and ready-made UI
A Firebase User has a fixed set of basic properties
User info is stored in a database separate from project data
There several events your app can react to
GoogleService-Info.plist
FirebaseApp.configure()
let authUI = FUIAuth.defaultAuthUI()!
authUI.providers = [
FUIGoogleAuth(), FUIFacebookAuth()
]
authUI.delegate = self
self.present(authUI.authViewController(), animated: true)
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
let sourceApplication = options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String?
if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication) ?? false {
return true
}
// other URL handling goes here.
return false
}
Handles user's signIn event and introduces callbacks for UI customization
func authUI(_ authUI: FUIAuth, didSignInWith user: User?, error: Error?) {
guard let user = user, error == nil else { return }
self.title = user.displayName
}
func authPickerViewController(forAuthUI authUI: FUIAuth) -> FUIAuthPickerViewController {
// return custom picker subclass
}
Auth object allows to implement custom flow for user authorisation
Auth.auth().addStateDidChangeListener { (auth, user) in
if let u = user {
print("Signed In as ", u.displayName)
try! Auth.auth().signOut()
} else {
print("Signed Out")
}
}
Auth.auth().signIn(withEmail: emailStr, password: passwordStr)
Provides a declarative rules language that allows you to define how your data should be structured, how it should be indexed, and when your data can be read from and written to
let storage = Storage.storage()
A reference can be thought of as a pointer to a file or catalog in the cloud
let storageRef = storage.reference()
var spaceRef = storageRef.child("images/space.jpg")
let path = spaceRef.fullPath;
let name = spaceRef.name;
let images = spaceRef.parent()
Files are stored in heirarchal manner
You can upload data from memory or files directly from your device
let localFile = URL(string: "path/to/image")!
let mountainsRef = storageRef.child("mountains.jpg")
let uploadTask = mountainsRef.putFile(from: localFile, metadata: nil) {
metadata, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL()
}
}
You cannot upload data with a reference to the root
let starsRef = storage.reference(withPath: "images/stars.jpg")
let downloadTask = starsRef.write(toFile: localURL) {
url, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Local file URL for "images/island.jpg" is returned
}
}
Upload and Download Tasks can be managed in a similar manner
let uploadTask = mountainsRef.putFile(from: localFile
uploadTask.pause()
uploadTask.resume()
uploadTask.cancel()
let observer = uploadTask.observe(.progress) {
snapshot in
// A progress event occured
}
All observers are removed automaticaly once the task is finished
let desertRef = storageRef.child("desert.jpg")
desertRef.delete { error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// File deleted successfully
}
}
SDWebImage provides an async image downloader with cache support
let reference = storageRef.child("images/stars.jpg")
let imageView: UIImageView = self.imageView
let placeholderImage = UIImage(named: "placeholder.jpg")
imageView.sd_setImage(with: reference, placeholderImage: placeholderImage)
Downloads image directly into imageView
Data is stored as JSON and synchronized in realtime to every connected client
"chats": {
"one": {
"title": "Historical Tech Pioneers",
"lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
"timestamp": 1459361875666
},
"two": { ... },
"three": { ... }
}
Represents a particular location in your Firebase Database
and can be used for reading or writing data to that Firebase Database location
Database.database().reference()
notesRef.child("01").setValue(["title": title])
Snapshots
notesRef.observeSingleEvent(of: .value, with: {
(snapshot) in
let value = snapshot.value as? [String:Any] ?? [:]
/* ... */
} ) {
(error) in
print(error.localizedDescription)
}
deletedRef.removeValue()
let updates = ["notes/01" : updNote.toDict(),
"total-notes" : notes.count ]
updatedRef.updateCildValues(updates)
notesObserver = notesRef.observe(.value, with: {
(snapshot) in
Note.storage.removeAll()
for child in snapshot.children {
let note = Note(withDict: child.value as? [String:Any] ?? [:])
Note.storage.append(note)
}
})
Always listen to the changes on the lowes level possible
notesRef.observe(.childAdded, with: { (snapshot) -> Void in
self.notes.append(snapshot)
})
notesRef.observe(.childRemoved, with: { (snapshot) -> Void in
let index = self.indexOfNote(snapshot)
self.notes.remove(at: index)
})
Listeners have to be removed explicitly to stop data syncronization
notesRef.removeAllObservers()
notesRef.child("special").removeObserver(withHandle: specialObserver)
Firebase can store syncronized data locally
Database.database().isPersistenceEnabled = true
Firebase synchronizes and stores a local copy of the data for active listeners but can also be forced to sync
Database.database().reference(withPath: "scores").keepSynced(true)