(Swift) 在 APP 關閉時,實現 Firebase 中 Firestore 的資料同步
目的:在 APP 關閉時,實現 Firebase 中 Firestore 的資料同步
Firebase 基本上傳資料的方法如下
有時候我們會希望 APP 關閉後,能夠即時更新 Firestore 中的一些資料,例如:玩家的上線狀態,這時候你就會需要這一篇文章
UserModel
假設你已經在 FireStore 有了資料,用於保存每個玩家的基本資料如下:
struct UserModel: Codable, Identifiable {
// Firestore 文檔 ID
@DocumentID var id: String?
// 使用者姓名
var name: String
// 使用者信箱
var email: String
// 登入的方法
var loginMethod: String
// 使否上線
var onlineStatus: Bool
// 勝利場次
var wins: Int
// 輸的場次
var losses: Int
// 剩餘金錢
var remainingMoney: Int
}
這次的目標就是希望在每次開啟 APP 時,即時更新 onlineStatus
的狀態為 true,並且在關閉 APP 時,將 onlineStatus
的狀態改為 false
ViewController
先到你需要更改 ViewController 中的 onlineStatus
,每當登入到 ViewController 就更新 onlineStatus
,更新的同時也將 userUID
保存到 userDefaults
中
override func viewDidLoad() {
super.viewDidLoad()
...
// 更新上線狀態為 true
let db = Firestore.firestore()
let userDocument = db.collection("users").document(viewModel.userUID())
userDocument.updateData(["onlineStatus": true])
// 將登入帳號存入 UserDefaults 中
let userDefaults = UserDefaults.standard
userDefaults.set(viewModel.userUID(), forKey: "userUID")
}
// 抓取現在使用者的 UID
func userUID() -> String {
guard let currentUser = Auth.auth().currentUser else { return "" }
return currentUser.uid
}
AppDelegate
在 AppDelegate 新增以下程式碼
var backgroundTask: UIBackgroundTaskIdentifier = .invalid
func applicationWillTerminate(_ application: UIApplication) {
// 啟動背景任務
backgroundTask = application.beginBackgroundTask {
// 當背景任務結束時的清理代碼
application.endBackgroundTask(self.backgroundTask)
self.backgroundTask = .invalid
}
// 確保背景任務結束
application.endBackgroundTask(backgroundTask)
backgroundTask = .invalid
}
SceneDelegate
在 SceneDelegate 新增以下的程式碼
記得要 import FirebaseFirestore
,從這就可以知道,為何要使用 userDefaults 來保存 userUID,這樣一來就能在 SceneDelegate 抓到每位使用者的 UID
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
let userDefaults = UserDefaults.standard
let userUID = userDefaults.string(forKey: "userUID")!
let db = Firestore.firestore()
let userDocument = db.collection("users").document(userUID)
// 更新上線狀態為 false
userDocument.updateData(["onlineStatus": false])
}
做完上述的動作後,就能即時更新 Firestore 中的 onlineStatus 的資料
但使用上述的方法可能不太好,如果今天沒有網路關閉 APP 時,Firestore 可能會無法完成更新,且在測試的時後,有極少數的狀況不會完成更新,所以我想可能還有更好的作法,來即時更新玩家的上線狀態,例如每幾分鐘檢查所有帳號的上線狀態。