我在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的问题。
是否有更好的方法可以使这些数据更加一致地保持同步?