在iOS和watchOS之间同步身份验证数据的最佳方式是什么?

时间:2017-02-28 18:50:41

标签: ios watchkit watch-os watchconnectivity wcsession

我在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的问题。

是否有更好的方法可以使这些数据更加一致地保持同步?

0 个答案:

没有答案