(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 可能會無法完成更新,且在測試的時後,有極少數的狀況不會完成更新,所以我想可能還有更好的作法,來即時更新玩家的上線狀態,例如每幾分鐘檢查所有帳號的上線狀態。

--

--