我在 iOS 和 watchOS 之间同步用户凭据时遇到问题。
我的基本设置是我的 iOS 应用程序和 watchOS 应用程序都需要与后端服务器通信,并且它们都需要访问令牌才能这样做。但是,用户只能在 iOS 应用上登录(因为需要输入用户名和密码)。
现在,当用户登录 iOS(或之后打开应用程序)时,我使用 updateApplicationContext() 将用户的凭据发送到 watchOS。用户注销时也会做类似的事情,如下:
func logInOnWatch() {
if WCSession.isSupported() {
session.activate()
var userInfo = [String : Any]()
userInfo["type"] = "logInConfirm"
userInfo[userKey.isLoggedIn] = true
let deviceUserID = KeychainAccess.password(for: userKey.ID, service: userKey.keyChain)
userInfo[userKey.ID] = deviceUserID
let accessTokenSecret = KeychainAccess.password(for: userKey.accessTokenSecret, service: userKey.keyChain)
userInfo[userKey.accessTokenSecret] = accessTokenSecret
do {
try session.updateApplicationContext(userInfo)
}
catch {
print(error)
}
}
}
func logOutOnWatch() {
if WCSession.isSupported() {
session.activate()
var dict = [String : Any]()
dict["type"] = "logInConfirm"
dict["logInStatus"] = "User Has Not Logged In"
do {
try session.updateApplicationContext(dict)
}
catch {
print(error)
}
}
}
然后我接收数据并更新手表端的界面如下:
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) {
if let contextType = applicationContext["type"] as? String {
switch contextType {
case "logInConfirm":
saveUserDataToDisk(from: applicationContext)
reloadRootControllersIfNeeded()
... // Handle other types of data
default:
return
}
}
}
func saveUserDataToDisk(from userInfo: [String : Any]) {
if let _ = userInfo[userKey.isLoggedIn] {
userDefaults.set(true, forKey: userKey.isLoggedIn)
if let token = userInfo[userKey.accessTokenSecret] as? String {
KeychainAccess.setPassword(token, for: userKey.accessTokenSecret, service: userKey.keyChain)
}
if let userID = userInfo[userKey.ID] as? String {
KeychainAccess.setPassword(userID, for: userKey.ID, service: userKey.keyChain)
}
}
else {
removeAllData()
}
}
func reloadRootControllersIfNeeded() {
if (userDefaults.object(forKey: userKey.isLoggedIn) == nil) {
/// Display the logged out controller if it isn't already the root controller.
if (loggedIn == nil) || loggedIn! {
WKInterfaceController.reloadRootControllers(withNames: ["LoggedOutController"], contexts: [self])
}
loggedIn = false
}
else {
/// Display the home controller if the logged out controller is the root controller.
if (loggedIn == nil) || !loggedIn! {
WKInterfaceController.reloadRootControllers(withNames: ["HomeController"], contexts: [self])
}
loggedIn = true
}
}
当用户登录和用户注销时,这一切都很好。
但是,在登录后使用该应用程序时,手表偶尔会将根控制器切换到已注销的控制器(可能是因为它收到一条消息,告诉它从用户默认值中删除登录标志,因此告诉它注销)。
使用 Xcode 没有很好的方法来捕捉这种情况,但它偶尔会发生。更糟糕的是,当我在 iOS 上打开应用程序(从标签栏控制器的 viewDidAppear 调用 logInOnWatch())时,手表没有更新。然后更新手表的唯一方法是注销并重新登录 iOS。只有这样,手表才会收到凭据和登录标志。
在应用程序的整个生命周期中还有其他实例,在这些实例中,一旦用户登录,我就会将用户数据从 iOS 发送到 watchOS,并且这些都可以正常工作。我想知道Apple如何处理手表上的用户默认设置是否存在问题,或者可能是WatchConnectivity的问题。
有没有更好的方法来更一致地保持这些数据同步?